Laravel 运行时类的功能扩展的实现
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 协议》,转载必须注明作者和本文链接