原文:Zephir類和對象 #類和對象 Zephir可以優化面向對象編程,經過使用Zephir可以讓你把方法和類寫入到PHP擴展中,從而避免常見的運行致命錯誤和警告,取而代之的是編譯錯誤。 ##類 每個Zephir文件必須實現一個且只能是一個類或者接口。Zephir的類接口跟PHP的類結構很是類似。php
namespace Test; /** * This is a sample class */ class MyClass { }
##類定義 如下類的限定是被容許的: ###Final:這個類不容許被繼承html
namespace Test; /** * This class cannot be extended by another class */ final class MyClass { }
###Abstract:該類禁止被實例化編程
namespace Test; /** * This class cannot be instantiated */ abstract class MyClass { }
##編寫方法 同PHP中同樣,使用function關鍵字來定義類的方法,能夠經過private、public、protected來定義方法的訪問權限。app
namespace Test; class MyClass { public function myPublicMethod() { // ... } protected function myProtectedMethod() { // ... } private function myPrivateMethod() { // ... } }
方法中能夠接受必選參數和可選參數,能夠設定參數的默認值來實現可選參數ide
namespace Test; class MyClass { /** * All parameters are required */ public function doSum1(a, b) { return a + b; } /** * Only 'a' is required, 'b' is optional and it has a default value */ public function doSum2(a, b = 3) { return a + b; } /** * Both parameters are optional */ public function doSum3(a = 1, b = 2) { return a + b; } /** * Parameters are required and their values must be integer */ public function doSum4(int a, int b) { return a + b; } /** * Static typed with default values */ public function doSum4(int a = 4, int b = 2) { return a + b; } }
##可選的null參數 Zephir確保方法參數會被賦值,經過null默認值會在運行時轉化到目標類型。如:null轉化到int時爲0,轉換到boolean時是false,轉化到string時是空字符串oop
public function foo(int a = null) { echo a; // if "a" is not passed it prints 0 } public function foo(boolean a = null) { echo a; // if "a" is not passed it prints false } public function foo(string a = null) { echo a; // if "a" is not passed it prints an empty string } public function foo(array a = null) { var_dump(a); // if "a" is not passed it prints an empty array }
##支持的權限控制修飾符優化
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; } }
你也能夠經過如下代碼實現相同功能ui
namespace App; class MyClass { protected myProperty { set, get, toString }; protected someProperty = 10 { set, get }; }
當編譯器在編譯生成時會自動生成相關屬性的設置和get方法,可是你不用一個一個的去編寫。下降編寫難度。 #返回類型的聲明 方法和接口能夠聲明返回類型,以下:this
namespace App; class MyClass { public function getSomeData() -> string { // this will throw a compiler exception // since the returned value (boolean) does not match // the expected returned type string return false; } public function getSomeOther() -> <App\MyInterface> { // this will throw a compiler exception // if the returned object does not implement // the expected interface App\MyInterface return new App\MyObject; } public function process() { var myObject; // the type-hint will tell the compiler that // myObject is an instance of a class // that implement App\MyInterface let myObject = this->getSomeOther(); // the compiler will check if App\MyInterface // implements a method called "someMethod" echo myObject->someMethod(); } }
一個方法也能夠擁有多個返回類型,當定義了多個返回類型時,請使用|符號來分割各個類型spa
namespace App; class MyClass { public function getSomeData(a) -> string | bool { if a == false { return false; } return "error"; } }
##返回類型 Void 若是一個方法的返回值被聲明爲void,則表示該方法不容許返回任何數據。
public function setConnection(connection) -> void { let this->_connection = connection; }
設置void返回值聲明後,若是有調用錯誤會產生編譯錯誤而不是運行錯誤,避免隱性的漏洞。
let myDb = db->setConnection(connection); myDb->execute("SELECT * FROM robots"); // this will produce an exception
##靜態/動態 的參數類型 在Zephir中能夠特別的指定變量類型,默認狀況下變量類型是動態的,若是指定了變量類型,Zephir會嘗試把傳入參數轉化成指定的類型。
public function filterText(string text, boolean escape=false) { //... }
以上方法在執行時的結果:
<?php $o->filterText(1111, 1); // OK $o->filterText("some text", null); // OK $o->filterText(null, true); // OK $o->filterText("some text", true); // OK $o->filterText(array(1, 2, 3), true); // FAIL
如今,大多數狀況下傳入一個錯誤類型的參數會拋出一個異常
<?php $o->filterText(1111, 1); // FAIL $o->filterText("some text", null); // OK $o->filterText(null, true); // FAIL $o->filterText("some text", true); // OK $o->filterText(array(1, 2, 3), true); // FAIL
儘量的定義參數的類型有助於程序編寫。 ##只讀變量 經過使用const關鍵字聲明能夠標明一個變量爲只讀變量,這種變量將不被容許在方法中被修改。
namespace App; class MyClass { // "a" is read-only public function getSomeData(const string a) { // this will throw a compiler exception let a = "hello"; } }
當一個變量被設定爲不可修改時,編譯器會對這個變量作最大化的優化 ##實現類的屬性 類中的變量稱之爲屬性(properties)。Zephir類屬性能夠映射到PHP類中,二者對於屬性的控制方法一致。
namespace App; class MyClass { // "a" is read-only public function getSomeData(const string a) { // this will throw a compiler exception let a = "hello"; } }
類中的非靜態屬性能夠經過->來修改和讀取值。
namespace Test; class MyClass { protected myProperty; public function setMyProperty(var myProperty) { let this->myProperty = myProperty; } public function getMyProperty() { return this->myProperty; } }
屬性能夠有默認值,可是默認值必須是靜態的且不依賴與運行時的變量、參數
namespace Test; class MyClass { protected myProperty1 = null; protected myProperty2 = false; protected myProperty3 = 2.0; protected myProperty4 = 5; protected myProperty5 = "my value"; }
##更新類的屬性 屬性的值能夠經過->引用來更新
let this->myProperty = 100;
Zephir會在編譯時檢查屬性是否存在,若是被操做的屬性不存在則會拋出以下錯誤:
CompilerException: Property '_optionsx' is not defined on class 'App\MyClass' in /Users/scott/utils/app/myclass.zep on line 62 this->_optionsx = options; ------------^
若是你想動態的建立一個屬性並複製的話,你可使用以下的方法去實現:
let this->{"myProperty"} = 100;
你也能夠經過使用變量去更新對應名稱的屬性值
let someProperty = "myProperty"; let this->{someProperty} = 100;
##讀取類的屬性 經過使用->來讀取
echo this->myProperty;
當須要更新屬性值時,能夠動態的讀取和設置值
//避免編譯器檢查屬性是否存在,動態的建立屬性 echo this->{"myProperty"} //經過變量名稱來讀取屬性 let someProperty="mProperty"; echo this->{someProperty};
##類常量 能夠定義類中的屬性爲常量,避免被修改。這種定義容許在php中直接使用
namespace Test; class MyClass{ const MYCONSTANT1=false; const MYCONSTANT2=1.0; }
類屬性常量能夠經過靜態屬性引用方式來讀取(::)
namespace Test; class MyClass{ const MYCONSTANT1=false; public function someMethod(){ return MyClass::MYCONSTANT1; } }
##調用類的方法 調用Zephir的方法可使用和PHP類方法的調用同樣的方式->
namespace Test; class MyClass{ protected function a(a,b){ return a-b; } public function b(c,d){ return this->a(c,d); } }
靜態方法必須使用靜態方法的操做符::
namespace Test; class MyClass { protected static function _someHiddenMethod(a, b) { return a - b; } public static function someMethod(c, d) { return self::_someHiddenMethod(c, d); } }
你也能夠動態的訪問某個類的方法:
namespace Test; class MyClass { protected adapter; public function setAdapter(var adapter) { let this->adapter = adapter; } public function someMethod(var methodName) { return this->adapter->{methodName}(); } }
##經過變量名來傳參(高端..) 咱們先定義以下的一個類,讓咱們來看看有什麼神奇的使用方法
namespace Test; class Image { public function chop(width = 600, height = 400, x = 0, y = 0) { //... } }
常規狀況下咱們是這樣去調用方法的
i->chop(100); // width=100, height=400, x=0, y=0 i->chop(100, 50, 10, 20); // width=100, height=50, x=10, y=20
使用變量名傳參的狀況下你能夠這樣寫
i->chop(width: 100); // width=100, height=400, x=0, y=0 i->chop(height: 200); // width=600, height=200, x=0, y=0 i->chop(height: 200, width: 100); // width=100, height=200, x=0, y=0 i->chop(x: 20, y: 30); // width=600, height=400, x=20, y=30
若是Zephir在編譯時不知道變量順序時,必須在運行時指定。
let i = new {someClass}(); i->chop(y:30, x: 20);
今天翻譯完成...