摘要:重載在中就大量應用了重載相關知識,如在中就用到了方法重載知識使用魔術方法來動態創建類中未定義或不可見的靜態方法。中通過引入魔術方法來實現動態的創建類屬性和方法,包括屬性重載的魔術方法和方法重載的魔術方法。
說明:本文主要講述PHP中重載概念,由于Laravel框架中經常使用這塊知識點,并且PHP的重載概念又與其他OOP語言如JAVA中重載概念不一樣,故復習并記錄相關知識點。同時,作者會將開發過程中的一些截圖和代碼黏上去,提高閱讀效率。
重載(overloading)在Laravel中就大量應用了重載相關知識,如在IlluminateSupportFacadesFacade中就用到了方法重載知識:使用魔術方法__callStatic()來動態創建類中未定義或不可見的靜態方法。PHP中重載概念與其他的OOP語言如JAVA語言中重載概念還不一樣,PHP中重載概念主要是:動態的創建類屬性和方法,而不是一般的類中方法名一樣而參數不一樣。PHP中通過引入魔術方法來實現動態的創建類屬性和方法,包括屬性重載的魔術方法和方法重載的魔術方法。當然,重載是在類的外部發生的,所以所有魔術方法必須聲明public,而且參數不能引用傳遞。
PHP中是可以動態創建一個類中未定義屬性或方法的,這也是PHP這個語言的一個比較靈活的特性,如:
class Person { } $person = new Person(); $person->name = "PHP"; echo $person->name.PHP_EOL; $person->age("18");
Person類中沒有屬性$name和方法age(),但PHP可以動態創建,echo出的$name值是"PHP",訪問未定義的age()方法并不報錯。
屬性重載PHP中引入了4個魔術方法來實現屬性重載:
__set(string $name, array $value)
__get(string $name)
__isset(string $name)
__unset(string $name)
1、當在類中定義魔術方法__set()時,給未定義或不可見屬性賦值時會先觸發__set(),可以使用__set()魔術方法來禁止動態創建屬性:
class Person { public function __set($name, $value) { if (isset($this->$name)) { return $this->$name = $value; } else { return null; } } } $person = new Person(); $person->name = "PHP"; echo $person->name.PHP_EOL;
這時想要動態創建$name屬性就不可以了,返回null。
2、當在類中定義魔術方法__get()時,當讀取未定義或不可見屬性時就觸發__get()方法:
class Person { private $sex; public function __set($name, $value) { if (isset($this->$name)) { return $this->$name = $value; } else { return null; } } public function __get($name) { return $name; } } $person = new Person(); $person->name = "PHP"; echo $person->name.PHP_EOL; echo $person->sex.PHP_EOL;
如果不寫魔術方法__get(),當讀取不可見屬性$sex就報錯,而這里返回的是name和sex字符串。
3、當在類中定義魔術方法__isset()時,當對未定義或不可見屬性調用isset()或empty()方法時,就會先觸發__isset()魔術方法:
class Person { private $sex; public function __set($name, $value) { if (isset($this->$name)) { return $this->$name = $value; } else { return null; } } public function __get($name) { return $name; } public function __isset($name) { echo $name; } } $person = new Person(); $person->name = "PHP"; echo $person->name.PHP_EOL; echo $person->sex.PHP_EOL; echo isset($person->address).PHP_EOL;
如果沒有魔術方法__isset()最后一行返回空,否則就觸發該魔術方法。
4、同樣的,魔術方法__unset()當使用unset()方法時觸發:
class Person { private $sex; public function __set($name, $value) { if (isset($this->$name)) { return $this->$name = $value; } else { return null; } } public function __get($name) { return $name; } public function __isset($name) { echo $name; } public function __unset($name) { echo $name.PHP_EOL; } } $person = new Person(); $person->name = "PHP"; echo $person->name.PHP_EOL; echo $person->sex.PHP_EOL; echo isset($person->address).PHP_EOL; unset($person->name);方法重載
上面是類屬性重載,當類方法重載時,PHP提供了兩個魔術方法:__call()和__callStatic(),__call()是動態創建對象方法觸發,__callStatic()是動態創建類方法觸發:
class Person { private $sex; public function __set($name, $value) { if (isset($this->$name)) { return $this->$name = $value; } else { return null; } } public function __get($name) { return $name; } public function __isset($name) { echo $name; } public function __unset($name) { echo $name.PHP_EOL; } public function __call(string $method, array $args) { echo $method."/".implode(",", $args).PHP_EOL; } public function __callStatic(string $method, array $args) { echo $method."/".implode(",", $args).PHP_EOL; } } $person = new Person(); $person->name = "PHP"; echo $person->name.PHP_EOL; echo $person->sex.PHP_EOL; echo isset($person->address).PHP_EOL; unset($person->name); $person->age("18"); Person::education("Master");
當調用對象方法age()時觸發__call()魔術方法,且$args是一個數組,是要傳遞給$method方法的參數。方法返回字符串:age/18和education/Master。
Laravel中方法重載使用在使用Laravel的Facade這種模式時,是通過Facade幫我們代理從容器Container中取出所需要的服務Service,就不需要通過$app["config"]這種方式取服務了,如:
$callback = Config::get("github.callback");
但是查看源碼 IlluminateSupportFacadesConfig,發現并沒有get()這個靜態方法:
利用上面知識,當調用一個類中未定義或不可見的靜態方法時,必然是調用了__callStatic()方法,發現IlluminateSupportFacadesFacade這個抽象類中定義了魔術方法__callStatic():
public static function __callStatic($method, $args) { $instance = static::getFacadeRoot(); if (! $instance) { throw new RuntimeException("A facade root has not been set."); } switch (count($args)) { case 0: return $instance->$method(); case 1: return $instance->$method($args[0]); case 2: return $instance->$method($args[0], $args[1]); case 3: return $instance->$method($args[0], $args[1], $args[2]); case 4: return $instance->$method($args[0], $args[1], $args[2], $args[3]); default: return call_user_func_array([$instance, $method], $args); } }其中,
/** * Get the root object behind the facade. * * @return mixed */ public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor());//這里調用Config::getFacadeAccessor(),返回"config",static是靜態延遲綁定 } /** * Resolve the facade root instance from the container. * * @param string|object $name * @return mixed */ protected static function resolveFacadeInstance($name) { if (is_object($name)) { return $name; } if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } //這里是使用$app["config"]從容器中解析,也就是實際上Facade貌似是幫我們從容器中解析Service,其實也是通過$app["config"]這種方式去解析。 //當然,有了Facade后,從容器中解析服務就不用受限于$app這個容器變量了。 return static::$resolvedInstance[$name] = static::$app[$name]; }看到這里,我們知道當使用Config::get()方法時,會從容器中解析出名稱為"config"這個Service,也就是這個Service中有我們需要的get()方法,那哪一個Service名字叫做"config"。實際上,觀察Laravel源碼包的目錄結構也知道在哪了:IlluminateConfigRepository,這個服務就是我們需要的,里面get()方法源碼:
/** * Get the specified configuration value. * * @param string $key * @param mixed $default * @return mixed */ public function get($key, $default = null) { return Arr::get($this->items, $key, $default); }既然這個服務Service叫做config,那么容器類Application剛啟動時就已經把所有需要的服務注冊進來了,并且取了名字。實際上,"config"服務是在IlluminateFoundationBootstrapLoadConfiguration注冊的,看bootstrap()方法源碼:
/** * Bootstrap the given application. * * @param IlluminateContractsFoundationApplication $app * @return void */ public function bootstrap(Application $app) { $items = []; // First we will see if we have a cache configuration file. If we do, we"ll load // the configuration items from that file so that it is very quick. Otherwise // we will need to spin through every configuration file and load them all. if (file_exists($cached = $app->getCachedConfigPath())) { $items = require $cached; $loadedFromCache = true; } $app->instance("config", $config = new Repository($items)); //在這里注冊名叫config的服務,服務實體是Repository類 // Next we will spin through all of the configuration files in the configuration // directory and load each one into the repository. This will make all of the // options available to the developer for use in various parts of this app. if (! isset($loadedFromCache)) { $this->loadConfigurationFiles($app, $config); } $app->detectEnvironment(function () use ($config) { return $config->get("app.env", "production"); }); date_default_timezone_set($config["app.timezone"]); mb_internal_encoding("UTF-8"); }這個啟動方法做了一些環境監測、時間設置和編碼設置。使用其他的Facade獲取其他Service也是這樣的過程。
總結:基本學習了PHP的重載知識后,對使用Laravel的Facade這個方式來獲取服務時有了更深入的了解。總之,多多使用Laravel來做一些東西和多多學習Laravel源碼并模仿之,也是一件有趣的事情。
歡迎關注Laravel-China。
RightCapital招聘Laravel DevOps
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21798.html
摘要:說明本文主要學習的模塊的源碼邏輯,把自己的一點點研究心得分享出來,希望對別人有所幫助。實際上,使用了的重載學習筆記之重載,通過魔術方法調用里的,而這個實際上就是,該中有方法,可以調用。 說明:本文主要學習Laravel的Filesystem模塊的源碼邏輯,把自己的一點點研究心得分享出來,希望對別人有所幫助。總的來說,Filesystem模塊的源碼也比較簡單,Laravel的Illumi...
摘要:總結本文主要學習了啟動時做的七步準備工作環境檢測配置加載日志配置異常處理注冊注冊啟動。 說明:Laravel在把Request通過管道Pipeline送入中間件Middleware和路由Router之前,還做了程序的啟動Bootstrap工作,本文主要學習相關源碼,看看Laravel啟動程序做了哪些具體工作,并將個人的研究心得分享出來,希望對別人有所幫助。Laravel在入口index...
摘要:類與對象基本概念如果在之后跟著的是一個包含有類名的字符串,則該類的一個實例被創建。如果該類屬于一個名字空間,則必須使用其完整名稱。如果一個類被聲明為,則不能被繼承。命名空間通過關鍵字來聲明。 類與對象 基本概念 new:如果在 new 之后跟著的是一個包含有類名的字符串,則該類的一個實例被創建。如果該類屬于一個名字空間,則必須使用其完整名稱。 Example #3 創建一個實例 ...
摘要:魔術方法知識點整理代碼使用語法編寫一構造函數和析構函數構造函數具有構造函數的類會在每次創建新對象時先調用此方法,所以非常適合在使用對象之前做一些初始化工作。在析構函數中調用將會中止其余關閉操作的運行。析構函數中拋異常會導致致命錯誤。 PHP魔術方法知識點整理 代碼使用PHP7.2語法編寫 一、構造函數和析構函數 __construct() 構造函數 __construct ([ mi...
摘要:使用了來表示該,該接口也是對的抽象,暴露了一些常用方法判斷是否滿足要求的方法的讀寫相關操作獲取元數據方法操作指針相關方法等等。本篇主要學習下相關使用。后續還會分享相關使用,到時見。 說明:本文主要學習guzzlehttp/guzzle package的使用,該package提供了一套發送HTTP請求API,就像phpunit package, mockery package, symf...
閱讀 1261·2023-04-25 19:10
閱讀 1140·2021-09-10 10:50
閱讀 3028·2021-09-02 15:21
閱讀 1383·2019-08-30 15:52
閱讀 1681·2019-08-30 13:56
閱讀 2077·2019-08-30 12:53
閱讀 1870·2019-08-28 18:22
閱讀 2115·2019-08-26 13:47