用PHP特性trait实现简易Laravel Facade

 3422

下面给大家介绍如何利用PHP trait实现简易Facade,希望对大家有所帮助!

简述

Facade 可以有效帮我实现方法的静态化。Laravel 大部分的扩展包都使用了 Facade

下面的简易 Facade 主要是利用 PHP 的特性 trait,魔术方法 __callStatic,反射类 ReflectionClass


使用场景

后台系统大部分都会有类似这样的操作:

  1. <?php
  2. $user = User::find($id);
  3. if (!$user) {
  4.     throw new \Expection("资源不存在");
  5. }

这样似乎没有什么问题,但是还会存在下面这样的:

  1. $article = Article::find($id);
  2. if (!$article) {
  3.     throw new \Expection("资源不存在");
  4. }
  5. $article->delete();

这样写法十分不优雅。


上代码

1、首先我们应该要有一个 Service

  1. <?php
  2. namespace App\Services;
  3. use App\Traits\ModeServiceTrait;
  4.  
  5. class ModelService extends BaseService
  6. {
  7.     use ModeServiceTrait;
  8. }

2、新建一个 Trait

trait 为了多继承而存在的,可以去 PHP官网 看文档。

  1. <?php
  2. namespace App\Traits;
  3. use \ReflectionClass;
  4. use \Exception;use \ReflectionException;
  5. use Illuminate\Database\Eloquent\Model;
  6. use App\Exceptions\ResourceException;
  7. /**
  8.  * @method static Model find(string $className, int $id, callable $callback = null)
  9.  *
  10.  * @see Model
  11.  * @package App\Services
  12.  */trait ModeServiceTrait{
  13.     /**
  14.      * 回调方法
  15.      *
  16.      * @param Model|null $model
  17.      * @param string $method
  18.      * @return Model
  19.      * @throws ResourceException
  20.      */
  21.     public static function callback(Model|null $model, string $method): Model    {
  22.         switch ($method)
  23.         {
  24.             case 'first':
  25.             case 'find':
  26.                 if (!$model) {
  27.                     throw new ResourceException("资源不存在");
  28.                 }
  29.                 break;
  30.  
  31.             default:
  32.  
  33.                 break;
  34.         }
  35.  
  36.         return $model;
  37.     }
  38.  
  39.     /**
  40.      * 调用不存在的方法时触发
  41.      *
  42.      * @param $method
  43.      * @param $args
  44.      * @return false|mixed
  45.      * @throws ReflectionException
  46.      * @throws ResourceException
  47.      * @throws Exception
  48.      */
  49.     public static function __callStatic($method, $args)
  50.     {
  51.         $className = $args[0];
  52.         $arg = $args[1];
  53.  
  54.         // 判断模型类是否存在
  55.         if (!class_exists($className)) {
  56.             throw new Exception("The class {$className} could not be found. from:" . __CLASS__);
  57.         }
  58.  
  59.         // 利用反射实例化其类
  60.         $reflection = new ReflectionClass($className);
  61.         $instance = $reflection->newInstanceArgs();
  62.  
  63.         // 调用该不存在的方法
  64.         $model = call_user_func_array([$instance, $method], [$arg]);
  65.  
  66.         // 如果存在复杂操作交给 callback
  67.         return isset($args[2]) ? $args[2]($model) : self::callback($model, $method);
  68.     }
  69. }

首先我们关注 __callStatic 这个魔术方法。 当调用不存在的静态方法时会触发该方法。和他相似的魔术方法是 __call。这是使用 __callStatic 是为了达到 Facade 的效果。

__callStatic 有两个回调参数 $method 是 被调用的且不存在的方法$args 是 $method 方法中所传递的参数(数组形式)。

这样一个简易的 trait 就完成了。


使用

我们新建一个 command

  1. $ php artisan make:command TestCommand

写入下面的内容

  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use App\Services\ModelService;
  5. use App\Models\Article\Article;
  6. class TestCommand extends Command{
  7.     /**
  8.      * The name and signature of the console command.
  9.      *
  10.      * @var string
  11.      */
  12.     protected $signature = 'test:test';
  13.  
  14.     /**
  15.      * The console command description.
  16.      *
  17.      * @var string
  18.      */
  19.     protected $description = 'a test';
  20.  
  21.     /**
  22.      * Create a new command instance.
  23.      *
  24.      * @return void
  25.      */
  26.     public function __construct()
  27.     {
  28.         parent::__construct();
  29.     }
  30.  
  31.     /**
  32.      * Execute the console command.
  33.      */
  34.     public function handle()
  35.     {
  36.         $article = ModelService::find(Article::class, 1);
  37.  
  38.         $article = ModelService::find(Article::class, 1, function ($model) {
  39.             return $model->load('author');
  40.         });
  41.     }
  42. }

其中的 Article 模型需要自己去创建。

接下来就可以看看效果了:

  1. $ php artisan test:test


结语

这样我们就抛弃了使用 abstract 抽象类,来达到了跟 Facade 一样的效果。同时也做到了代码复用。
这样使用程序会多走很多步,但是跟优雅比起来,性能什么的都无所谓了。

表达不是很清楚,需要自己深入体会了。


本文网址:https://www.zztuku.com/detail-10870.html
站长图库 - 用PHP特性trait实现简易Laravel Facade
申明:本文转载于《learnku》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐

    PHP实现排序功能总结