原文連接: https://learnku.com/laravel/t...
討論請前往專業的 Laravel 開發者論壇: https://learnku.com/Laravel
Laravel將PHP應用到了一個全新的水平,爲您打造下一個項目提供了出色的開發體驗(DX)。所以,一些人將其稱爲「魔術」。php
今天,我將向您展現Laravel的一個技巧,魔術方法。laravel
重要的是,要了解魔術方法並非Laravel獨有的,而是能夠在任何PHP應用中使用。Laravel剛好有一些最有趣的魔術方法用例。git
魔術方法是在PHP中聲明的任何類中均可以使用的方法,它提供了在類中實現附加功能的方法。程序員
這裏有一個很好的定義:github
魔術方法永遠不會被程序員調用——實際上,PHP將在後臺調用該方法。這就是爲何它們被稱爲「魔術」方法——由於它們歷來沒有被直接調用,它們容許程序員作一些很是強大的是事情。
總共有15中魔術方法:編程
class MyClass { public function __construct() {} public function __destruct() {} public function __call() {} public function __callStatic() {} public function __get() {} public function __set() {} public function __isset() {} public function __unset() {} public function __sleep() {} public function __wakeup() {} public function __toString() {} public function __invoke() {} public function __set_state() {} public function __clone() {} public function __debuginfo() {} }
若是您用PHP作過一些面向對象的編程,那麼您必定知道 __construct
方法,這是一個魔術方法。因此您一直在使用魔術方法。數組
您還注意到,全部的魔術的方法都是以「__」爲前綴的。閉包
今天,咱們不會深刻研究這些方法,而只會深刻了解整個Laravel代碼庫中使用的那些有趣的方法。若是其餘人對此感興趣,請隨時查看下面的文檔👇函數
PHP: Méthodes magiques - Manualoop
__get()
Laravel中的模型很是特別。它們不將屬性數據存儲爲類的直接屬性,而是存儲在protected $attributes
屬性中,該屬性是模型所保存的全部數據的相關數組。
讓咱們看看簡單的PHP類和Laravel模型訪問屬性的區別。
<?php /** * PHP中的普通用戶類(非Laravel)將只是一個具備上述屬性的類 */ class NormalUser { public $firstName = 'Alice'; } $normalUser = new NormalUser; $normalUser->firstName; // 將返回'Alice'
<?php namespace App; use Illuminate\Database\Eloquent\Model; /** * Laravel中的一個user類 */ class LaravelUser extends Model { /** * 注意,咱們將全部屬性數據存儲在一個單獨的數組中 */ protected $attributes = [ 'firstName' => 'Alice', ]; } $laravelUser = new LaravelUser; $laravelUser->firstName; // 依然返回'Alice'
咱們能夠看到,上面的PHP和Laravel類的行爲徹底相同。
然而,在Laravel的例子中,屬性不像普通PHP那樣存儲,而是集中在一個名爲$attributes
的屬性中。咱們仍然設法訪問正確的數據,可是如何訪問呢?
這一切都是可能的,這是由於_get
魔術方法。讓咱們本身嘗試實現一個簡單的例子。
<?php class NormalUser { /** * 像在Laravel中那樣聲明屬性 */ protected $attributes = [ 'firstName' => 'Alice', ]; /** * __get 函數接收一個參數 * 它將會是你想要訪問的屬性名 * 在這個例子中是 $key = "firstName" */ public function __get(string $key) { return $this->attributes[$key]; } } $normalUser = new NormalUser; $normalUser->firstName; // 將會返回 'Alice'
咱們作到了! 🎉
咱們須要注意,只有在類中找不到具備匹配名稱的屬性時,纔會調用魔術方法_get
。這是一種後備方法,當PHP在類中找不到所訪問的屬性時調用。所以,在下面的示例中,根本不會調用魔術方法_get
。
<?php class NormalUser { public $firstName = 'Bob'; protected $attributes = [ 'firstName' => 'Alice', ]; public function __get($key) { return $this->attributes[$key]; } } $normalUser = new NormalUser; /** * 因爲類中存在該屬性,將會返回 Bob * 因此該例子中沒有調用到魔術方法__get */ $normalUser->firstName;
有更多的事情在幕後發生。若是你想更多地瞭解 Laravel 的模型是如何確切地使用 __get
的,你能夠查看下面的源代碼。
__set()
當試圖設置的屬性沒有在類中聲明時,使用魔術方法_set
。讓咱們再次看看normal PHP類和Laravel中model模型的區別。
<?php class NormalUser { public $firstName = 'Alice'; } $normalUser = new NormalUser; $normalUser->firstName = 'Bob'; $normalUser->firstName; // Will return 'Bob'
<?php namespace App; use Illuminate\Database\Eloquent\Model; class LaravelUser extends Model { protected $attributes = [ 'firstName' => 'Alice', ]; } $laravelUser = new LaravelUser; $laravelUser->firstName = 'Bob'; $laravelUser->firstName; // Will return 'Bob' as well
如咱們所見,在此示例中,咱們仍然嘗試影響Bob
的值,該值在類中實際上不存在但位於屬性$ attributes
中。讓咱們嘗試使用魔術方法__ set
<?php class NormalUser { public $attributes = [ 'firstName' => 'Alice', ]; /** * The magic method __set receives the $name you want to affect the value on * and the value */ public function __set($key, $value) { $this->attributes[$key] = $value; } } $normalUser = new NormalUser; $normalUser->firstName = 'Bob'; /** * As we don't have the __get magic method define in this example for simplicity sake, * we will access the $attributes directly */ $normalUser->attributes['firstName']; // Will return 'Bob'
如今咱們開始!咱們在Laravel中成功實施了__ get
和__ set
魔術方法的基本用法!他們只需幾行代碼就能完成!
請記住,這些魔術方法儘量簡單,而沒必要涉及太多細節,由於除了那些還有更多而不只僅是用例,若是您對它的工做原理感到好奇,我邀請您親自作一些探索! (若是您有任何疑問,也能夠隨時在Twitter上與我聯繫)
一樣,若是您想進一步挖掘,請在此處連接到源代碼
讓咱們繼續最後一個也是最有趣的一個事! 🙌
__call()
& __callStatic()
當調用的方法在類中找不到時,__call()
會被調用。 在laravel中,該魔術方法方法使宏在 php 中成爲可能。
我不會深刻討論宏的全部細節,但若是您感興趣,這裏有一篇很好的文章解釋瞭如何在 Laravel 應用程序中使用它們👇
讓咱們試着看看如何編寫一個簡單的宏示例。
<?php class NormalUser { public $firstName = 'Alice'; public $lastName = 'Bob'; } $normalUser = new NormalUser; $normalUser->fullName(); // 因爲沒有聲明 "fullName" 方法,這將會拋出錯誤
使用 __call
,能夠定義一個包含閉包函數的數組,在咱們開發時能夠程序化地添加到應用裏。
<?php class NormalUser { public $firstName = 'Alice'; public $lastName = 'Bob'; /** * 將咱們的宏初始化爲一個空數組,後面再賦值 */ public static $macros = []; /** * 定義一個添加新宏的方法 * 第一個參數是咱們想要定義的宏的名字 * 第二個參數是調用宏時將會被執行的閉包函數 */ public static function addMacro($name, $macro) { static::$macros[$name] = $macro; } /** * "__call" 接收兩個參數, * $name 是被調用的函數名稱,好比 「fullName」 * $arguments 是傳遞給函數的全部參數,這裏咱們使用了一個空數組,由於咱們的函數不用傳參 */ public function __call(string $name, array $arguments) { /** * 經過名稱獲取到宏 */ $macro = static::$macros[$name]; /** * 而後經過參數執行宏 * 備註:調用以前,咱們須要將閉包綁定到 「$this」,從而使宏方法在一樣的上下文中執行 */ return call_user_func_array($macro->bindTo($this, static::class), $arguments); } } $normalUser = new NormalUser; $normalUser->fullName(); // 這裏會中斷,由於咱們既沒有定義 「fullName」 宏,也沒有 「fullName」 方法存在。 /** * 添加 「fullName」 宏方法 */ NormalUser::addMacro('fullName', function () { return $this->firstName.' '.$this->lastName; }); $normalUser->fullName(); // 如今,返回 「Alice Bob」
宏要比那個複雜一些,可是咱們設法使用 __call
魔術方法來建立一個宏的簡單工做版本。
除了對於靜態方法, __callStatic
和 __call
是徹底同樣的。
若是你打算本身再深刻研究,這裏有宏的特性源代碼。
因此說碼農們,當你第一次用 Laravel 會感受它神奇是對的,可是經過深刻查看源代碼,你會理解魔法是如何在場景背後施展的。
就像現實生活中的魔法,沒有道理的事情是不會發生的,在代碼中就更加是了。程序運行的背後老是有着一行代碼在執行,只不過須要你去發現它。
原文連接: https://learnku.com/laravel/t...
討論請前往專業的 Laravel 開發者論壇: https://learnku.com/Laravel