1. __toString:php
當對象被打印時,若是該類定義了該方法,則打印該方法的返回值,不然將按照PHP的缺省行爲輸出打印結果。該方法相似於Java中的toString()。數組
<?php class TestClass { public function __toString() { return "This is TestClass::__toString.\n"; } } $testObj = new TestClass(); print $testObj;
運行結果以下:閉包
Stephens-Air:Desktop$ php Test.php
This is TestClass::__toString.
2. __get和__set:函數
這兩個方法用於處理類中未聲明的屬性訪問。當對象使用者試圖訪問未聲明的對象屬性時,__get()會被調用,並帶有一個包含要訪問的屬性名稱字符串做爲參數。不管從__get()方法返回什麼,都會直接返回給調用者,就如同帶有該值的屬性存在同樣。另外須要注意的是,若是屬性存在,可是其訪問可見性爲private或protected,那麼這兩個攔截方法一樣會被調用,反之,若是屬性存在切可訪問,那麼直接訪問屬性便可,這兩個方法將再也不會被調用。如下爲__get()攔截方法的示例代碼:學習
<?php class TestClass { private $privateField; public $publicField; public function __construct() { $this->privateField = "This is a private Field.\n"; $this->publicField = "This is a public Field.\n"; } public function __get($property) { print "__get() is called.\n"; $method = "get${property}"; if (method_exists($this, $method)) { return $this->$method(); } return "This is undefined field.\n"; } public function getPrivateField() { return $this->privateField; } } $testObj = new TestClass(); print $testObj->privateField; print $testObj->undefinedField; print $testObj->publicField;
運行結果以下:this
Stephens-Air:Desktop$ php Test.php
__get() is called.
This is a private Field.
__get() is called.
This is undefined field.
This is a public Field.
__set()方法被調用的規則和__get()基本相同,差異是用於攔截未定義或不可見類屬性的賦值操做。另外,該方法接收兩個參數,分別是屬性名稱和要設定的值。見以下代碼示例:spa
<?php class TestClass { private $privateField; public $publicField; public function __construct() { $this->privateField = "This is a private Field.\n"; $this->publicField = "This is a public Field.\n"; } public function __get($property) { print "__get() is called.\n"; $method = "get${property}"; if (method_exists($this, $method)) { return $this->$method(); } return "This is an undefined field.\n"; } public function __set($property, $value) { print "__set is called.\n"; $method = "set${property}"; if (method_exists($this, $method)) { $this->$method($value); } else { print "This is an undefined field.\n"; } } public function getPrivateField() { return $this->privateField; } public function setPrivateField($value) { $this->privateField = $value; } } $testObj = new TestClass(); $testObj->privateField = "This is a private Field after set.\n"; $testObj->undefinedField = "This is a undefined Field after set.\n"; $testObj->publicField = "This is a public Field after set.\n"; print $testObj->privateField; print $testObj->undefinedField; print $testObj->publicField;
運行結果以下:code
Stephens-Air:Desktop$ php Test.php
__set is called.
__set is called.
This is an undefined field.
__get() is called.
This is a private Field after set.
__get() is called.
This is an undefined field.
This is a public Field after set.
3. __isset和__unset:對象
這兩個攔截方法被調用的規則和__get()和__set()很是相似,只是用於類中不存在或不可見屬性被isset()和unset()兩個全局方法應用時纔會被分別觸發。 blog
<?php class TestClass { private $privateField; public $publicField; public function __construct() { $this->privateField = "Defined private field"; $this->publicField = "Defined public field"; } public function __isset($property) { print "__isset is called.\n"; return isset($this->$property); } public function __unset($property) { print "__unset is called.\n"; if (isset($this->$property)) { unset($this->$property); } } } $testObj = new TestClass(); print 'isset($testObj->privateField) is '.(isset($testObj->privateField) ? "true" : "false")."\n"; print 'isset($testObj->undefinedField) is '.(isset($testObj->undefinedField) ? "true" : "false")."\n"; print 'isset($testObj->publicField) is '.(isset($testObj->publicField) ? "true" : "false")."\n"; print "After unset......\n"; //下面兩個函數調用後,$testObj的兩個對象屬性均會變爲不可用。 //另外從輸出結果來看,__unset方法僅僅被調用一次,由於publicField爲可見屬性,因此__unset不會因該屬性而被調用。 unset($testObj->privateField); unset($testObj->publicField); print 'isset($testObj->privateField) is '.(isset($testObj->privateField) ? "true" : "false")."\n"; print 'isset($testObj->publicField) is '.(isset($testObj->publicField) ? "true" : "false")."\n";
運行結果以下:
Stephens-Air:Desktop$ php Test.php __isset is called. isset($testObj->privateField) is true __isset is called. isset($testObj->undefinedField) is false isset($testObj->publicField) is true After unset...... __unset is called. __isset is called. isset($testObj->privateField) is false __isset is called. isset($testObj->publicField) is false
4. __call:
__call()方法是一個很是有用但又很是容易被濫用的攔截方法。當對象使用者試圖訪問當前對象未定義的成員函數時,__call()會被自動調用,同時傳遞兩個參數,分別爲函數名稱和傳遞給調用函數的全部參數(數組)。__call方法返回的任何值都會返回給函數調用者,就如同該成員函數真實存在同樣。下面給出一個很是有用的委託示例。
<?php class DelegateClass { function printMessage($arg1, $arg2) { print "DelegateClass:delegatedMethod is called.\n"; print '$arg1 = '.$arg1.'and $arg2 = '.$arg2."\n"; } } class TestClass { private $delegateObj; public function __construct() { $this->delegateObj = new DelegateClass(); } public function __call($method, $args) { $this->delegateObj->$method($args[0],$args[1]); } } $testObj = new TestClass(); $testObj->printMessage("hello","world");
運行結果以下:
Stephens-Air:Desktop$ php Test.php
DelegateClass:delegatedMethod is called.
$arg1 = helloand $arg2 = world
從以上示例能夠看出,TestClass並未聲明printMessage成員方法,可是經過__call()方法的巧妙橋接直接傳遞給了委託對象。我的認爲該技巧爲雙刃劍,切勿過分使用。
5. 回調函數:
回調函數的應用場景無須多述,在C/C++中充斥着無數的回調函數典型用例。 這裏只是簡單給出PHP中回調函數的使用規則。見以下示例代碼和關鍵性註釋:
<?php class Product { public $name; public $price; public function __construct($name, $price) { $this->name = $name; $this->price = $price; } } class ProcessSale { private $callbacks; function registerCallback($cb) { if (!is_callable($cb)) { throw new Exception("callback not callable."); } $this->callbacks[] = $cb; } function sale($product) { print "{$product->name}: processing \n"; foreach ($this->callbacks as $cb) { //如下兩種調用方式都可。 call_user_func($cb, $product); $cb($product); } } } $logger = function($product) { print " logging ({$product->name})\n"; }; $processor = new ProcessSale(); $processor->registerCallback($logger); $processor->sale(new Product("shoes",6)); print "\n"; $processor->sale(new Product("coffee",6));
運行結果以下:
Stephens-Air:Desktop$ php Test.php
shoes: processing
logging (shoes)
logging (shoes)
coffee: processing
logging (coffee)
logging (coffee)
6. use(閉包):
在Javascript中存在大量的閉包應用,PHP中的閉包則是經過use關鍵字來完成的。對於閉包這個概念自己而言,簡要的說就是函數內的代碼能夠訪問其父做用域中的變量。見以下示例代碼和關鍵性註釋:
<?php class Product { public $name; public $price; public function __construct($name, $price) { $this->name = $name; $this->price = $price; } } class ProcessSale { private $callbacks; function registerCallback($cb) { if (!is_callable($cb)) { throw new Exception("callback not callable."); } $this->callbacks[] = $cb; } function sale($product) { print "{$product->name}: processing \n"; foreach ($this->callbacks as $cb) { $cb($product); } } } class Totalizer { static function warnAmount($amt) { $count = 0; //注意這裏的$amt和$count均爲閉包變量,其中&$count是以引用的形式傳遞的,即一旦函數內部修改了該變量的值, //那麼下次再訪問該閉包變量時,$count將爲以前調用中修改後的值。 return function($product) use($amt, &$count) { $count += $product->price; print " count: $count\n"; if ($count > $amt) { print " high price reached: {$count}\n"; } }; } } $processor = new ProcessSale(); $processor->registerCallback(Totalizer::warnAmount(8)); $processor->sale(new Product("shoes",6)); $processor->sale(new Product("coffee",6));
運行結果以下:
shoes: processing count: 6 coffee: processing count: 12 high price reached: 12
注:該Blog中記錄的知識點,是在我學習PHP的過程當中,遇到的一些PHP和其餘面嚮對象語言相比比較獨特的地方,或者是對我本人而言確實須要簿記下來以備後查的知識點。雖然談不上什麼深度,可是仍是但願能與你們分享。