Laravel 執行時類的功能擴充套件的實現
通常實現類功能擴充套件有以下的方法
- 使用類繼承的方法,在子類中新增功能
- 使用類組合的方法,把基礎的類作為擴充套件功能類的一個屬性,來實現擴充套件功能的目的
- 利用 php 的魔術方法
__call
和__callStatic
來動態的實現功能擴充套件
通過繼承實現功能擴充套件
Fish
相對於 Animal
擴充套件出了 swim
方法
class Animal
{
public $name;
public function __construct($name) { $this->name = $name; }}
class Fish extends Animal
{
public function swim() { return 'fish swiming'; } }
通過組合的方法實現功能擴充套件
class Animal
{
public $name;
public function __construct($name) { $this->name = $name; }}
class Fish
{
public $animal;
public function __construct(Animal $animal) { $this->animal = $animal; }
public function swim() { return 'fish swiming'; }}
$animal = new Animal("suzi");
$fish = new Fish($animal);
echo $fish->animal->name;
echo $fish->swim();
通過類的魔術方法實現類功能擴充套件
class Animal
{
public $name;
public function __construct($name) { $this->name = $name; }
public function __call($method,$params){ if ($method === 'swim'){ return 'swiming'; } trigger_error(sprintf("method %s not found",$method)); }}
$animal = new Animal("suzi");
echo $animal->swim();
//$animal->whatEver(); trigger error
通過繼承和組合的方式實現類功能擴充套件的優點是:程式碼清晰,明確的知道類有哪些功能,
缺點是:沒辦法根據條件擴充套件不同的功能。魔術方法的方式的優缺點恰好和前兩者相反。
laravel 動態擴充套件功能
laravel 動態擴充套件功能是通過一個名為 Macroable
的 trait
實現的。 所有使用了 trait Macroable
都有動態擴充套件類的功能。
主要有3個靜態的API
macro($name,$macro)
動態注入方法mixin($mixin, $replace = true)
合併$mixin
物件的public
和protected
方法hasMacro($name)
判斷是否擴充套件過指定名稱的功能
class EmptyMacroable
{
use Illuminate\Support\Traits\Macroable; public $foo = 'foo';}
EmptyMacroable::macro('hello',function (){
return 'hello world';});
$foo = new EmptyMacroable();
echo $foo->hello();// output: hello world
class Mixed {
protected function methodOne(){ return function (){ return $this->foo; }; }}
EmptyMacroable::mixin(new Mixed());
echo "\n";
echo $foo->methodOne();// output: foo
動態擴充套件功能在 laravel 中的應用
laravel framework 的底層類幾乎都使用了 trait Macroable
。常用的有 Request
,response
等。
這些類都具有動態擴充套件功能的能力。下面是一個擴充套件 Request
功能的例子
\Illuminate\Http\Request::macro("isBackend",function (){
return str_contains($this->pathInfo??'',"/backend");});
$request = new \Illuminate\Http\Request();
var_dump($request->isBackend());// output: false
本作品採用《CC 協議》,轉載必須註明作者和本文連結