摘要:魔術(shù)方法知識點(diǎn)整理代碼使用語法編寫一構(gòu)造函數(shù)和析構(gòu)函數(shù)構(gòu)造函數(shù)具有構(gòu)造函數(shù)的類會(huì)在每次創(chuàng)建新對象時(shí)先調(diào)用此方法,所以非常適合在使用對象之前做一些初始化工作。在析構(gòu)函數(shù)中調(diào)用將會(huì)中止其余關(guān)閉操作的運(yùn)行。析構(gòu)函數(shù)中拋異常會(huì)導(dǎo)致致命錯(cuò)誤。
PHP魔術(shù)方法知識點(diǎn)整理
代碼使用PHP7.2語法編寫一、構(gòu)造函數(shù)和析構(gòu)函數(shù) __construct() 構(gòu)造函數(shù)
__construct ([ mixed $args [, $... ]] ) : void
具有構(gòu)造函數(shù)的類會(huì)在每次創(chuàng)建新對象時(shí)先調(diào)用此方法,所以非常適合在使用對象之前做一些初始化工作。
如果子類中定義了構(gòu)造函數(shù)則不會(huì)隱式調(diào)用其父類的構(gòu)造函數(shù)。要執(zhí)行父類的構(gòu)造函數(shù),需要在子類的構(gòu)造函數(shù)中調(diào)用 parent::__construct()。如果子類沒有定義構(gòu)造函數(shù)則會(huì)從父類繼承。Code
當(dāng)子類的 __construct() 與父類 __construct() 具有不同參數(shù)不同時(shí),PHP 不會(huì)產(chǎn)生錯(cuò)誤信息。這一點(diǎn)與其他的類方法不同。
書籍類
/** * 書籍類 * Class Book */ class Book { /** * 書籍名稱 * @var string $name */ public $name; /** * 書籍作者 * @var string $author */ public $author; /** * 構(gòu)造函數(shù) * @param $name * @param $author */ public function __construct(string $name, string $author) { $this->name = $name; $this->author = $author; } }
計(jì)算機(jī)書籍類繼承自Book類,且增加了一個(gè)屬性 $category
/** * 計(jì)算機(jī)書籍類 * Class ComputerBook */ class ComputerBook extends Book { /** * 計(jì)算機(jī)書籍多了分類屬性 * @var string $category */ public $category; /** * 構(gòu)造函數(shù) * 這里的構(gòu)造函數(shù)幣父類的構(gòu)造函數(shù)多了一個(gè)參數(shù),但是PHP并不會(huì)報(bào)錯(cuò)。 * 而其他的類方法在這種情況下會(huì)報(bào)錯(cuò)。 * @param $name * @param $author * @param $category */ public function __construct(string $name, string $author, string $category) { parent::__construct($name, $author); $this->category = $category; } }
$book = new Book("茶館", "老舍"); echo <<name} 書籍作者: {$book->author} --- TXT ; $computerBook = new ComputerBook("高性能MySQL","Baron", "數(shù)據(jù)庫"); echo << name} 書籍作者: {$computerBook->author} 書籍分類: {$computerBook->category} --- TXT ;
書籍名稱: 茶館 書籍作者: 老舍 --- 書籍名稱: 高性能MySQL 書籍作者: Baron 書籍分類: 數(shù)據(jù)庫 ---__destruct() 析構(gòu)函數(shù)
__destruct ( void ) : void
析構(gòu)函數(shù)會(huì)在到某個(gè)對象的所有引用都被刪除或者當(dāng)對象被顯式銷毀時(shí)執(zhí)行。
如果子類中定義了析構(gòu)函數(shù)則不會(huì)隱式調(diào)用其父類的析構(gòu)函數(shù)。要執(zhí)行父類的析構(gòu)函數(shù),必須在子類的析構(gòu)函數(shù)體中顯式調(diào)用 parent::__destruct()。如果子類沒有定義析構(gòu)函數(shù)則會(huì)從父類繼承。Code
析構(gòu)函數(shù)即使在使用 exit() 終止腳本運(yùn)行時(shí)也會(huì)被調(diào)用。
在析構(gòu)函數(shù)中調(diào)用 exit() 將會(huì)中止其余關(guān)閉操作的運(yùn)行。
析構(gòu)函數(shù)中拋異常會(huì)導(dǎo)致致命錯(cuò)誤。
析構(gòu)函數(shù)即使在使用 exit() 終止腳本運(yùn)行時(shí)也會(huì)被調(diào)用。
/** * 房子類 * Class House */ class House { /** * 析構(gòu)函數(shù) */ public function __destruct() { echo "要開始拆房子了 "; $this->dismantleRoof(); $this->demolishWall(); } /** * 拆除屋頂 */ private function dismantleRoof() { echo "屋頂被拆除 "; } /** * 推掉墻 */ private function demolishWall() { echo "墻被推到 "; } } // 新建一座房子 $house = new House(); // 腳本停止運(yùn)行 exit();
要開始拆房子了 屋頂被拆除 墻被推到
在析構(gòu)函數(shù)中調(diào)用 exit() 將會(huì)中止其余關(guān)閉操作的運(yùn)行。
/** * 別墅類 * Class House */ class Villa extends House { /** * 析構(gòu)函數(shù) */ public function __destruct() { $this->demolishSwimmingPool(); // 拆掉游泳池后后悔了,不想繼續(xù)拆了 exit(); parent::__destruct(); } /** * 拆掉游泳池 */ private function demolishSwimmingPool() { echo "拆掉游泳池 "; } } // 新建一棟別墅 $villa = new Villa(); // 腳本停止運(yùn)行 exit();
拆掉游泳池
析構(gòu)函數(shù)中拋異常會(huì)導(dǎo)致致命錯(cuò)誤。
/** * 大廈類 * Class House */ class Mansion extends House { /** * 析構(gòu)函數(shù) */ public function __destruct() { $this->evacuateCrowd(); parent::__destruct(); } /** * 疏散大廈里的人 */ private function evacuateCrowd() { throw new Exception("大廈里還有人,不能拆!"); } } // 新建一座大廈 $mansion = new Mansion(); // 腳本停止運(yùn)行 exit();
PHP Fatal error: Uncaught Exception: 大廈里還有人,不能拆!二、對象復(fù)制 __clone()
__clone ( void ) : void
通過 clone 關(guān)鍵字克隆對象,當(dāng)復(fù)制完成時(shí),如果對象定義了 __clone() 方法,則新創(chuàng)建的對象(復(fù)制生成的對象)中的 __clone() 方法會(huì)被調(diào)用。
對象中的 __clone() 方法不能被直接調(diào)用。Code
當(dāng)對象被復(fù)制后,PHP 5 會(huì)對對象的所有屬性執(zhí)行一個(gè)淺復(fù)制(shallow copy)。所有的引用屬性仍然會(huì)是一個(gè)指向原來的變量的引用。此時(shí)我們需要在 __clone 中強(qiáng)制復(fù)制一份對象中的引用屬性。
/** * Class MyCloneable */ class MyCloneable { public $objectA; public $objectB; function __clone() { echo "MyCloneable::__clone "; // 強(qiáng)制復(fù)制一份this->objectA, 否則仍然指向同一個(gè)對象 $this->objectA = clone $this->objectA; } } /** * Class SubObject */ class SubObject { /** * 靜態(tài)計(jì)數(shù)器,對象每被實(shí)例化或clone一次,則+1 * @var int */ public static $counter = 0; public $instance; public function __construct() { echo "SubObject::__construct "; $this->instance = ++ self::$counter; } public function __clone() { echo "SubObject::__clone "; $this->instance = ++ self::$counter; } }
$myCloneable = new MyCloneable(); echo "實(shí)例化對象SubObject,并復(fù)制給 $myCloneable->objectA : "; $myCloneable->objectA = new SubObject(); echo "實(shí)例化對象SubObject,并復(fù)制給 $myCloneable->objectB : "; $myCloneable->objectB = new SubObject(); echo "復(fù)制對象 $myCloneable "; $myCloneable2 = clone $myCloneable; echo "------------------- "; echo "原始對象: "; print_r($myCloneable); echo "復(fù)制的對象: "; print_r($myCloneable2);
實(shí)例化對象SubObject,并復(fù)制給 $myCloneable->objectA : SubObject::__construct 實(shí)例化對象SubObject,并復(fù)制給 $myCloneable->objectB : SubObject::__construct 復(fù)制對象 $myCloneable MyCloneable::__clone SubObject::__clone ------------------- 原始對象: MyCloneable Object ( [objectA] => SubObject Object ( [instance] => 1 ) [objectB] => SubObject Object ( [instance] => 2 ) ) 復(fù)制的對象: MyCloneable Object ( [objectA] => SubObject Object ( [instance] => 3 ) [objectB] => SubObject Object ( [instance] => 2 ) )三、重載魔術(shù)方法
PHP中的重載與其它絕大多數(shù)面向?qū)ο笳Z言不同。傳統(tǒng)的重載是用于提供多個(gè)同名的類方法,但各方法的參數(shù)類型和個(gè)數(shù)不同。
PHP的重載(overloading)是指動(dòng)態(tài)地創(chuàng)建類屬性和方法。是通過魔術(shù)方法(magic methods)來實(shí)現(xiàn)的。
當(dāng)調(diào)用當(dāng)前環(huán)境下不可訪問(未定義或不可見)的類屬性或方法時(shí),重載方法會(huì)被調(diào)用。
所有的重載方法都必須被聲明為 public,且參數(shù)都不能通過引用傳遞。
屬性重載的魔術(shù)方法有:__set(), __get(), __isset(), __unset()。
方法重載的魔術(shù)方法有:__call(), __callStatic()
在給不可訪問屬性賦值時(shí),__set() 會(huì)被調(diào)用。
public __set ( string $name , mixed $value ) : void
$name 為要賦值的屬性名,$value 為屬性值。
__get()讀取不可訪問屬性的值時(shí),__get() 會(huì)被調(diào)用。
public __get ( string $name ) : mixed
$name 為要訪問的屬性名。
__isset()當(dāng)對不可訪問屬性調(diào)用 isset() 或 empty() 時(shí),__isset() 會(huì)被調(diào)用。
public __isset ( string $name ) : bool
$name 為屬性名。
在除 isset() 外的其它語言結(jié)構(gòu)中無法使用重載的屬性,這意味著當(dāng)對一個(gè)重載的屬性使用 empty() 時(shí),重載魔術(shù)方法將不會(huì)被調(diào)用。為避開此限制,必須將重載屬性賦值到變量再使用 empty()。
__unset()當(dāng)對不可訪問屬性調(diào)用 unset() 時(shí),__unset() 會(huì)被調(diào)用。
public __unset ( string $name ) : void
$name 為屬性名。
Codeclass Property { /** * 被重載的數(shù)據(jù)保存在該屬性 * @var array */ private $data = []; /** * 已經(jīng)定義的屬性不會(huì)調(diào)用重載魔術(shù)方法 * @var int */ public $declared = 1; /** * 只有從類外部訪問屬性時(shí),才會(huì)調(diào)用重載魔術(shù)方法 * @var int */ private $hidden = 2; /** * @param $name * @param $value */ public function __set($name, $value) { echo "Setting "{$name}" to "{$value}" "; $this->data[$name] = $value; } /** * @param $name * @return mixed|null */ public function __get($name) { echo "Getting "$name" "; if (array_key_exists($name, $this->data)) { return $this->data[$name]; } } /** * @param $name * @return bool */ public function __isset($name) { echo "Is "$name" set? "; return isset($this->data[$name]); } /** * @param $name */ public function __unset($name) { echo "Unsetting "$name" "; unset($this->data[$name]); } /** * 非魔術(shù)方法 * @return int */ public function getHidden() { return $this->hidden; } }
$obj = new Property; echo "為不存在的屬性a賦值:"; $obj->a = 1; echo "獲取不存在的屬性a的值:", $obj->a . " "; echo "---------------------------- "; echo "使用empty判斷屬性a是否為空 "; var_dump(empty($obj->a)); echo "使用isset判斷屬性a是否存在 "; var_dump(isset($obj->a)); echo "---------------------------- "; echo "使用unset注銷掉屬性a的值 "; unset($obj->a); echo "使用empty判斷屬性a是否為空 "; var_dump(empty($obj->a)); echo "使用isset判斷屬性a是否存在 "; var_dump(isset($obj->a)); echo "---------------------------- "; echo "獲取可訪問的屬性declared的值:", $obj->declared . " "; echo "為不可訪問的屬性hidden賦值0,此時(shí)調(diào)用了魔術(shù)方法__set() "; $obj->hidden = 0; echo "通過public方法getHidden()從類內(nèi)部訪問私有屬性hidden的值,不會(huì)調(diào)用魔術(shù)方法: ", $obj->getHidden() . " "; echo "獲取不可訪問的屬性hidden的值,此時(shí)調(diào)用了魔術(shù)方法__get(): " , $obj->hidden . " ";
為不存在的屬性a賦值:Setting "a" to "1" 獲取不存在的屬性a的值:Getting "a" 1 ---------------------------- 使用empty判斷屬性a是否為空 Is "a" set? Getting "a" /vagrant/magic/overloading.php:119: bool(false) 使用isset判斷屬性a是否存在 Is "a" set? /vagrant/magic/overloading.php:122: bool(true) ---------------------------- 使用unset注銷掉屬性a的值 Unsetting "a" 使用empty判斷屬性a是否為空 Is "a" set? /vagrant/magic/overloading.php:130: bool(true) 使用isset判斷屬性a是否存在 Is "a" set? /vagrant/magic/overloading.php:133: bool(false) ---------------------------- 獲取可訪問的屬性declared的值:1 為不可訪問的屬性hidden賦值0,此時(shí)調(diào)用了魔術(shù)方法__set() Setting "hidden" to "0" 通過public方法getHidden()從類內(nèi)部訪問私有屬性hidden的值,不會(huì)調(diào)用魔術(shù)方法: 2 獲取不可訪問的屬性hidden的值,此時(shí)調(diào)用了魔術(shù)方法__get(): Getting "hidden" 0方法重載 __call()
在對象中調(diào)用一個(gè)不可訪問的方法時(shí),__call() 會(huì)被調(diào)用。
public __call ( string $name , array $arguments ) : mixed
$name 參數(shù)是要調(diào)用的方法名稱。$arguments 參數(shù)是一個(gè)枚舉數(shù)組,包含著要傳遞給方法 $name 的參數(shù)。
__callStatic()調(diào)用一個(gè)不可訪問的類靜態(tài)方法時(shí),__callStatic() 會(huì)被調(diào)用。
public static __callStatic ( string $name , array $arguments ) : mixed
$name 參數(shù)是要調(diào)用的方法名稱。$arguments 參數(shù)是一個(gè)枚舉數(shù)組,包含著要傳遞給方法 $name 的參數(shù)。
Codeclass Method { public function __call($name, $arguments) { // 注意: $name 的值區(qū)分大小寫 echo "調(diào)用對象不可訪問的方法 "$name" ", implode(", ", $arguments). " "; } public static function __callStatic($name, $arguments) { // 注意: $name 的值區(qū)分大小寫 echo "調(diào)用不可訪問的類靜態(tài)方法 "$name" ", implode(", ", $arguments). " "; } }
$obj = new Method; $obj->run("參數(shù)1", "參數(shù)2", "參數(shù)3"); Method::run("參數(shù)1", "參數(shù)2", "參數(shù)3");
調(diào)用對象不可訪問的方法 "run" 參數(shù)1, 參數(shù)2, 參數(shù)3 調(diào)用不可訪問的類靜態(tài)方法 "run" 參數(shù)1, 參數(shù)2, 參數(shù)3四、序列化魔術(shù)方法 __sleep()
public __sleep ( void ) : array
使用 serialize() 函數(shù)對對象進(jìn)行序列化時(shí),若類中存在魔術(shù)方法 __sleep() ,則會(huì)先被調(diào)用 __sleep(),然后才執(zhí)行序列化操作。
此功能可以用于清理對象,并返回一個(gè)包含對象中所有應(yīng)被序列化的變量名稱的數(shù)組。如果該方法未返回任何內(nèi)容,則 NULL 被序列化,并產(chǎn)生一個(gè) E_NOTICE 級別的錯(cuò)誤。
__sleep() 方法常用于提交未提交的數(shù)據(jù),或類似的清理操作。同時(shí),如果有一些很大的對象,但不需要全部保存,這個(gè)功能就很好用。
__sleep() 不能返回父類的私有成員的名字。這樣做會(huì)產(chǎn)生一個(gè) E_NOTICE 級別的錯(cuò)誤。可以用 Serializable 接口來替代。__wakeup()
__wakeup ( void ) : void
使用 unserialize() 函數(shù)對對象進(jìn)行反序列化時(shí),若類中存在魔術(shù)方法 __wakeup() ,則會(huì)先被調(diào)用 __wakeup() ,然后才執(zhí)行反序列化操作。
在反序列化操作中,__wakeup() 方法常用于重新建立數(shù)據(jù)庫連接,或執(zhí)行其它初始化操作。
class Connection { /** * 數(shù)據(jù)庫連接資源 * @var */ protected $link; /** * 連接數(shù)據(jù)庫所需要的屬性 * @var */ private $server, $username, $password, $db; /** * 構(gòu)造函數(shù),建立數(shù)據(jù)庫連接 * unserialize 執(zhí)行反序列化時(shí)不會(huì)調(diào)用構(gòu)造函數(shù) * @param $server * @param $username * @param $password * @param $db */ public function __construct($server, $username, $password, $db) { $this->server = $server; $this->username = $username; $this->password = $password; $this->db = $db; $this->connect(); } /** * 連接數(shù)據(jù)庫 */ private function connect() { $this->link = mysqli_connect($this->server, $this->username, $this->password); mysqli_select_db($this->db, $this->link); } /** * 使用serialize序列化對象時(shí),只保存以下四個(gè)對象屬性 * @return array */ public function __sleep() { return ["server", "username", "password", "db"]; } /** * unserialize 執(zhí)行反序列化時(shí)不會(huì)調(diào)用構(gòu)造函數(shù) * 因此使用 __wakeup 函數(shù)重新進(jìn)行數(shù)據(jù)庫連接 */ public function __wakeup() { $this->connect(); } }五、其他魔術(shù)方法 __toString()
public __toString ( void ) : string
當(dāng)對象被當(dāng)做字符串使用時(shí),調(diào)用 __toString() 方法,該方法必須返回一個(gè)字符串。
若對象未定義 __toString() 方法,或 __toString() 方法返回值不是字符串,則會(huì)產(chǎn)生 E_RECOVERABLE_ERROR 級別的致命錯(cuò)誤。
不能在 __toString() 方法中拋出異常。這么做會(huì)導(dǎo)致致命錯(cuò)誤。Code
class ToString { public $foo; public function __construct($foo) { $this->foo = $foo; } public function __toString() { return $this->foo; } } $class = new ToString("Hello World!"); echo $class;
Hello World!__invoke()
__invoke ([ $... ] ) : mixed
當(dāng)嘗試以調(diào)用函數(shù)的方式調(diào)用一個(gè)對象時(shí),__invoke() 方法會(huì)被自動(dòng)調(diào)用。
Codeclass CallableClass { function __invoke($foo) { return $foo; } } $callable = new CallableClass(); echo $callable("Hello World! "); var_dump(is_callable($callable));
Hello World! /vagrant/magic/__invoke.php:19: bool(true)
class UncallableClass { } $uncallable = new UncallableClass(); var_dump(is_callable($uncallable));
/vagrant/magic/__invoke.php:27: bool(false)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31678.html
摘要:使用中文函數(shù)名和變量名面積長寬長寬面積合法,輸出中文符號函數(shù)名。類型聲明類型聲明允許函數(shù)在調(diào)用時(shí)要求參數(shù)為特定類型。需要使用自己的包裝函數(shù)來將這些結(jié)構(gòu)用作可變函數(shù)。匿名函數(shù)目前是通過類來實(shí)現(xiàn)的。 一、函數(shù)的定義 1. 函數(shù)的命名規(guī)則 函數(shù)名可以包含字母、數(shù)字、下劃線,不能以數(shù)字開頭。 function Func_1(){ } //合法 function func1(){ } //合法 ...
摘要:繼上一篇面試常考內(nèi)容之面向?qū)ο蟀l(fā)表后,今天更新,需要的可以直接點(diǎn)擊文字進(jìn)行跳轉(zhuǎn)獲取。析構(gòu)函數(shù),當(dāng)對象被銷毀時(shí)調(diào)用。 PHP面試專欄正式起更,每周一、三、五更新,提供最好最優(yōu)質(zhì)的PHP面試內(nèi)容。繼上一篇PHP面試常考內(nèi)容之面向?qū)ο螅?)發(fā)表后,今天更新(2),需要(1)的可以直接點(diǎn)擊文字進(jìn)行跳轉(zhuǎn)獲取。整個(gè)面向?qū)ο笪恼碌慕Y(jié)構(gòu)涉及的內(nèi)容模塊有: 一、面向?qū)ο笈c面向過程有什么區(qū)別?二、面向?qū)?..
摘要:是決定正則表達(dá)式匹配規(guī)則的主要部分。二分隔符分隔符的選擇當(dāng)使用函數(shù)的時(shí)候,正則表達(dá)式必須由分隔符閉合包裹。果分隔符經(jīng)常在正則表達(dá)式內(nèi)出現(xiàn),最好使用其他分隔符來提高可讀性。需要將一個(gè)字符串放入正則表達(dá)式中使用時(shí),可以用函數(shù)對其進(jìn)行轉(zhuǎn)義。 一、簡介 1. 什么是正則表達(dá)式 正則表達(dá)式(Regular Expression)就是用某種模式去匹配一類字符串的一種公式。正則表達(dá)式使用單個(gè)字符串來...
摘要:消息隊(duì)列技術(shù)介紹后端掘金一消息隊(duì)列概述消息隊(duì)列中間件是分布式系統(tǒng)中重要的組件,主要解決應(yīng)用耦合異步消息流量削鋒等問題。的內(nèi)存優(yōu)化后端掘金聲明本文內(nèi)容來自開發(fā)與運(yùn)維一書第八章,如轉(zhuǎn)載請聲明。 消息隊(duì)列技術(shù)介紹 - 后端 - 掘金一、 消息隊(duì)列概述 消息隊(duì)列中間件是分布式系統(tǒng)中重要的組件,主要解決應(yīng)用耦合、異步消息、流量削鋒等問題。實(shí)現(xiàn)高性能、高可用、可伸縮和最終一致性架構(gòu)。是大型分布式系...
摘要:聲明靜態(tài)變量時(shí)不能用表達(dá)式的結(jié)果對其賦值正確錯(cuò)誤使用表達(dá)式的結(jié)果賦值錯(cuò)誤使用表達(dá)式的結(jié)果賦值靜態(tài)變量與遞歸函數(shù)靜態(tài)變量提供了一種處理遞歸函數(shù)的方法。 一、變量的定義 1. 變量的命名規(guī)則 變量名可以包含字母、數(shù)字、下劃線,不能以數(shù)字開頭。 $Var_1 = foo; // 合法 $var1 = foo; // 合法 $_var1 = foo; // 合法 $Var-1 = foo; /...
閱讀 1578·2021-11-02 14:42
閱讀 2320·2021-10-11 10:58
閱讀 667·2021-09-26 09:46
閱讀 2917·2021-09-08 09:35
閱讀 1413·2021-08-24 10:01
閱讀 1240·2019-08-30 15:54
閱讀 3610·2019-08-30 15:44
閱讀 1802·2019-08-30 10:49