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 动态扩展功能是通过一个名为 Macroabletrait 实现的。 所有使用了 trait Macroable 都有动态扩展类的功能。

主要有3个静态的API

  • macro($name,$macro) 动态注入方法
  • mixin($mixin, $replace = true) 合并 $mixin 对象的 publicprotected 方法
  • 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。常用的有 Requestresponse 等。
这些类都具有动态扩展功能的能力。下面是一个扩展 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 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!