Zephir入門 —— 語法篇

概述

Zephir的語法跟PHP很類似,因此這裏不會把官網的文檔照搬過來翻譯一遍,而是會把一些Zephir相較於PHP比較特別的語法挑出來說一下。若是想要要完整學習Zephir的語法,沒有比官網的文檔更好的地方了。php

基本語法

Zephir的文件後綴名爲zep,每一個文件都必須包含且只能包含一個類。每一個類必須有一個命名空間,且目錄結構必須跟類名和命名空間匹配。例以下面的目錄結構:html

mylibrary/
        router/
                exception.zep # MyLibrary\Router\Exception
        router.zep # MyLibrary\Router

那麼exception.zep的命名空間和類名以下:express

phpnamespace MyLibrary\Router;

class Exception extends \Exception
{

}

Zephir裏的變量名不須要像PHP那樣帶$符號,且有兩種聲明的方式:數組

// 可使用var來定義變量,或者指定具體的變量類型
var a;
int b;
bool c = true;

// 能夠在一行裏聲明多個變量
var a = "hello", b = 0, c;

要修改變量,屬性或者數組的值,須要使用let關鍵字。閉包

let name = "Tony";           // 變量
let this->name = "Tony";     // 對象屬性
let data["name"] = "Tony";   // 數組
let self::_name = "Tony";    // 靜態變量

Zephir不支持全局變量,也不容許訪問用戶域的全局變量,可是能夠訪問PHP的超級全局變量:函數

var price = _POST["price"];

var requestMethod = _SERVER["REQUEST_METHOD"];

變量類型

Zehpir支持動態和靜態類型。oop

動態類型

動態類型變量跟PHP同樣,能夠在賦值後修改成不一樣類型的值。動態類型變量必須用var來聲明。學習

var a, b, c;

// 初始化變量
let a = "hello", b = false;

// 改變它們的值
let a = 10, b = "140";

// 對它們進行操做
let c = a + b;

Zephir不會檢查整型的溢出,若是要操做比較大的數字,可使用浮點型或者靜態型變量'unsigned long':fetch

unsigned long my_number = 2147483648;

Zephir不支持在字符串裏使用變量的方式,你可使用拼接方式:優化

var name = "peter";

echo "hello: " . name;

數組的定義要用中括號[],且字符串型的鍵須要使用雙引號:

let myArray = [1, 2, 3];
let myHash = [0: "first", 1: true, 2: null];
let myHash = ["first": 7.0, "second": "some string", "third": false];

靜態變量

靜態變量一旦聲明類型後就不能再改變。雖然失去了動態型變量的靈活性,可是在編譯時靜態變量能進行更多的優化。

Zephir支持如下的靜態類型:

  • boolean: A boolean expresses a truth value. It can be either ‘true’ or ‘false’.
  • integer: Signed integers. At least 16 bits in size.
  • unsigned integer: Unsigned integers. At least 16 bits in size.
  • char: Smallest addressable unit of the machine that can contain basic character set.
  • unsigned char: Same size as char, but guaranteed to be unsigned.
  • long: Long signed integer type. At least 32 bits in size.
  • unsigned long: Same as long, but unsigned.
  • float/double: Double precision floating-point type. The size is platform-dependent.
  • string: A string is series of characters, where a character is the same as a byte.
  • unsigned long: Same as long, but unsigned.
  • array: An structure that can be used as hash, map, dictionary, collection, stack, etc.

布爾型,非布爾值會自動轉化爲true或者false:

boolean a;

let a = true,
    a = 100, // 自動轉換爲true
    a = null, // 自動轉換爲false
    a = "hello"; // 拋出編譯器異常

整型:

int a;

let a = 50,
    a = -70,
    a = 100.25, // 自動轉換爲100
    a = null, // 自動轉換爲0
    a = false, // 自動轉換爲0
    a = "hello"; // 拋出編譯器異常

無符號整型,帶符號整型的值會自動轉換爲無符號。另外要注意的是,無符號整型的最大值要比普通整型大一倍,因此在把無符號整型的值賦予普通整型時要注意下:

uint a, int b;

let a = 50,
    a = -70, // 自動轉換爲70

let a = 2147483648,
    b = a; // 可能會丟失數據

長整型/無符號長整型變量的值範圍是普通整型/無符號整型的兩倍,除此之外跟普通整型/無符號整型一致。

ulong a, long b;

let a = 4294967296,
    b = a; // 可能會丟失數據

字符型:

har ch, string name = "peter";

let ch = name[2]; // 存儲't'
let ch = 'Z'; // 須要用單引號

字符串:

string a;

let a = "",
    a = "hello", // 使用用雙引號
    a = 'A', // 自動轉換爲"A"
    a = null; // 自動轉換爲""

更詳細的類型語法請看這裏:http://zephir-lang.com/types.html

操做符

Zephir支持的運算符基本跟PHP一致:

// 算術運算符
// Zephir支持PHP中除了`$a ** $b`(PHP 5.6纔開始支持)這種方式外的算術運算符。
let c = a + b;

// 比較運算符
// Zephir支持的比較運算符跟PHP一致(除了PHP 7增長支持的兩個比較運算符外)。
if a == b {
    return 0;
} 

// 邏輯運算符
// Zephir支持`&&`、`||`和`!`這三個邏輯運算符,但不支持PHP裏`And`、`Or`和`Xor`這三個邏輯運算符。
if a && b || !c {
    return -1;
}

// 位運算符
// 跟PHP一致
if a & SOME_FLAG {
    echo "has some flag";
}

// 三元運算符
// 跟PHP一致
let b = a == 1 ? "x" : "y";

而後,Zephir還支持emptyisset等特殊的運算符:

// empty
// 若是表達式的值爲null、空字符串或者空數組,則爲empty
let someVar = "";
if empty someVar {
    echo "is empty!";
}

// isset
// 用於檢查數組的索引或者對象的屬性是否已定義
// 功能更相似於PHP中的array_key_exists方法
let someArray = ["a": 1, "b": 2, "c": 3];
if isset someArray["b"] {
    echo "yes, it has an index 'b'\n";
}

// fetch
// 用於簡化在PHP中如下的操做:
if (isset($myArray[$key])) {
    $value = $myArray[$key];
    echo $value;
}
// 使用fetch能夠用如下代碼實現,只有在key存在的狀況下,fetch才返回true:
if fetch value, myArray[key] {
    echo value;
}

// typeof
// 用於檢查變量的類型
if (typeof str == "string") {
    echo str;
}

更詳細的操做符語法請看這裏:http://zephir-lang.com/operators.html

數組

數組可使用關鍵字vararray進行聲明:

var a = []; // 類型能夠改變
array b = []; // 運行過程當中,類型不能夠改變

數組使用中括號進行建立,操做方式跟PHP同樣:

let elements = [];

let elements = [1, 3, 4];

let elements = ["first", 2, true];

let elements[0] = "bar";

let elements = ["foo": "bar", "bar": "foo"];

let foo = elements["foo"];

更詳細的數組操做語法請看這裏:http://zephir-lang.com/arrays.html

類和對象

前面說過,每一個zephir文件都必須包含一個類,並且只能包含一個類。

Zehpir的類支持finalabstract兩個修飾符,修飾符的做用跟PHP中的一致,例如:

namespace Test;

/**
 * 這個類不能被擴展
 */
final class MyClass
{

}

方法

類的成員方法支持的可見性修飾符也跟PHP一致,支持publicprotectedprivate,但Zephir強制方法必須顯式的帶上修飾符。

同時方法還支持finaldeprecated兩個修飾符:

// 這個方法不能被重寫
public final function foo()
{   
}

// 調用此方法會拋出E_DEPRECATED 異常
public deprecated function foo()
{  
}

方法的參數也支持PHP中可選參數的方式,同時也支持靜態類型:

public function doSum(a, b = 3)
{
    return a + b;
}

public function doSum2(int a = 4, int b = 2)
{
    return a + b;
}

使用靜態類型參數時,若是傳入的參數類型不一致,Zephir會試圖對傳入值進行類型的轉換。若是基於某些考慮不想Zephir自動去作這個事情,咱們能夠經過添加一個!號禁止這個行爲:

public function filterText(string! text, boolean escape=false)
{
    //...
}

另外咱們還能經過const關鍵字設置參數爲只讀:

// a爲只讀
public function getSomeData(const string a)
{
    // 這裏會拋出編譯錯誤
    let a = "hello";
}

Zephir還提供了方法返回類型的提示功能,使得編譯器能夠知道方法返回的類型:

namespace App;

class MyClass
{
    public function getSomeData() -> string
    {
        // 這裏會拋出編譯異常。由於返回值是布爾型,跟期待的返回類型不一致
        return false;
    }

    public function getSomeOther() -> <App\MyInterface>
    {
        // 這裏會拋出編譯異常,若是返回的對象不是App\MyInterface接口的一個實現
        return new App\MyObject;
    }

    public function process()
    {
        var myObject;

        // 類型提示會告訴編譯器myObject是App\MyInterface的一個實例
        let myObject = this->getSomeOther();

        // 編譯器會檢查App\MyInterface是否實現了一個叫someMethod的方法
        echo myObject->someMethod();
    }

    // 一個方法能夠有多個的返回類型,使用|進行分隔
    public function getSomeData2(a) -> string | bool
    {
        if a == false {
            return false;
        }
        return "error";
    }

    // 若是返回類型爲void,則表示此方法不容許返回任何數據
    public function setConnection(connection) -> void
    {
        let this->_connection = connection;
    }

}

屬性

類的屬性一樣支持publicprotectedprivate三個修飾符,並且必須顯式指定:

namespace Test;

class MyClass
{

    public myProperty1;
    protected myProperty2;
    private myProperty3;

    // 屬性能夠賦予默認值,可是這個值必須在編譯的時候就能知道而不須要依賴於運行環境
    protected myProperty4 = 5;
    protected myProperty5 = "my value";

    public function setMyProperty1(var myProperty)
    {
        // 修改屬性的值
        let this->myProperty1 = myProperty;
    }

    public function getMyProperty1()
    {
        // 讀取屬性的值
        return this->myProperty1;
    }

}

Zephir還提供了一個快捷的方式去實現Getter和Setter,例以下面的代碼:

namespace App;

class MyClass
{
    protected myProperty {
        set, get, toString
    };

    protected someProperty = 10 {
        set, get
    };

}

至關於:

namespace Test;

class MyClass
{
    protected myProperty;

    protected someProperty = 10;

    public function setMyProperty(myProperty)
    {
        this->myProperty = myProperty;
    }

    public function getMyProperty()
    {
        return this->myProperty;
    }

    public function setSomeProperty(someProperty)
    {
        this->someProperty = someProperty;
    }

    public function getSomeProperty()
    {
        return this->someProperty;
    }

    public function __toString()
    {
        return this->myProperty;
    }

 }

另外常量的使用也是支持的:

namespace Test;

class MyClass
{

    const MYCONSTANT1 = false;
    const MYCONSTANT2 = 1.0;

    public function someMethod()
    {
        return MyClass::MYCONSTANT1;
    }
}

更詳細的類和對象的使用方式請看這裏:http://zephir-lang.com/oop.html

內置方法

Zephir自身也內置了很多的方法,這些方法基本都是PHP中某些方法的OO實現。例如:

public function foo(string! s)
{
    return strlen(s);
}

// 使用內置方法
public function foo(string! s)
{
    return s->length();
}

更詳細的內置方法使用方式請看這裏:http://zephir-lang.com/builtin-methods.html

流程控制

條件語句

條件判斷語句中,ifswitch語句跟PHP相似,但須要注意的是,條件表達式的括號能夠省略:

if a > 100 {
    echo "to big";
} elseif a < 0 {
    echo "to small";
} else {
    echo "ok";
}

switch count(items) {
}

循環語句

循環語句中,用whileloopfor三種語句。

while語句跟PHP差很少,loop爲Zephir增長的語句,用於建立一個無限的循環:

let n = 40;
loop {
    let n -= 2;
    if n % 5 == 0 { break; }
    echo x, "\n";
}

for的用法跟PHP有很大不一樣,例如:

// 循環數組
for item in ["a", "b", "c", "d"] {
    echo item, "\n";
}

let items = ["a": 1, "b": 2, "c": 3, "d": 4];

for key, value in items {
    echo key, " ", value, "\n";
}

// 遍歷字符串
string language = "zephir"; char ch;

for ch in language {
    echo "[", ch ,"]";
}

三種循環語句中均支持break語句和continue語句。

文件包含

Zephir中也提供了相似PHP中require語句的語句:

if file_exists(path) {
    require path;
}

注意這個語句只能用於包含PHP文件,而不能包含zephir文件。

更詳細的流程控制語法請看這裏:http://zephir-lang.com/control.html

異常處理

異常處理跟PHP也相似:

try {

    // 能夠在這裏拋出異常
    throw new \Exception("This is an exception");

} catch \Exception, e {

    // 異常處理
    echo e->getMessage();
}

若是不須要的話,保存異常信息的變量e能夠省略:

try {

    throw new \Exception("This is an exception");

} catch \Exception {

    echo e->getMessage();
}

同時捕捉不一樣類型的異常:

try {

    throw new \Exception("This is an exception");

} catch RuntimeException|Exception, e {

    echo e->getMessage();
}

更詳細的異常處理的使用方式請看這裏:http://zephir-lang.com/exceptions.html

調用PHP函數

能夠直接調用PHP中內置的函數,例如調用base64_encode函數:

namespace MyLibrary;

class Encoder
{

    public function encode(var text)
    {
        if strlen(text) != 0 {
            return base64_encode(text);
        }
        return false;
    }
}

用戶本身定義的函數也能夠調用:

namespace MyLibrary;

class Encoder
{

    public function encode(var text)
    {
        if strlen(text) != 0 {
            if function_exists("my_custom_encoder") {
                return my_custom_encoder(text);
            } else {
                return base64_encode(text);
            }
        }
        return false;
    }
}

因爲PHP的函數只接收和返回動態變量,因此若是你傳入靜態變量的話,Zephir會隱式的建立一個臨時變量用於函數的調用。而返回的結果若是要賦值給靜態變量的話,須要做適當的類型轉換:

namespace MyLibrary;

class Encoder
{

    public function encode(string text)
    {
        string encoded = "";

        if strlen(text) != 0 {
            let encoded = (string) base64_encode(text);
            return '(' . encoded . ')';
        }
        return false;
    }
}

最後,若是咱們須要動態的對函數進行調用,可使用如下的方式:

namespace MyLibrary;

class Encoder
{

    public function encode(var callback, string text)
    {
        return {callback}(text);
    }
}

更詳細的函數的調用方法請看這裏:http://zephir-lang.com/functions.html

閉包

Zephir裏也支持閉包和匿名函數,你能夠把它返回給PHP:

namespace MyLibrary;

class Functional
{

    public function map(array! data)
    {
        return function(number) {
            return number * number;
        };
    }
}

也能夠直接調用:

namespace MyLibrary;

class Functional
{

    public function map(array! data)
    {
        return data->map(function(number) {
            return number * number;
        });
    }
}

另外Zephir還提供了一個短語法用來定義閉包:

namespace MyLibrary;

class Functional
{

    public function map(array! data)
    {
        return number => number * number;
    }
}

參考

http://zephir-lang.com/index.html

相關文章
相關標籤/搜索