在 Parent 中包含 Class 基于 Child Class

Include Class in Parent Based on Child Class

我有一个扩展基本控制器 class 的 child 控制器 class。在 child 中,我定义了一个静态命名空间字符串,它指向模型 class 我想在调用基础 class 中的函数时使用。现在,我必须使用 call_user_func 在正确的模型 class 上调用函数。代码看起来像这样:

Child Class

class RolesController extends Controller
{
    const RESOURCE_NAME = 'roles';
    const MODEL = 'Role';
}

Parent Class

class Controller extends BaseController
{

    private $model;

    public function __construct()
    {
        $this->model = 'App\Models\' . static::MODEL;
    }

    public function getAll(Request $request)
    {
        $objects = call_user_func([$this->model, 'getAll'], [
            Model::GET_OPTION_FORMAT => true
        ]);

        return Response::success([
            static::RESOURCE_NAME => $objects
        ]);
    }
}

我不禁认为这种设计模式是不正确的。有没有更好的方法来完成我想做的事情而不必依赖 call_user_func?我找不到类似的问题,因为我正在努力寻找描述这个问题的词。如果有人能指出我正确的方向,将不胜感激。

长答案

模型 classes 上的静态方法使这变得麻烦。更简洁的方法可能如下所示:

class RolesController extends Controller
{
    const RESOURCE_NAME = 'roles';
    const MODEL = App\Models\Role::class;
}


class Controller extends BaseController
{

    private $model;

    public function __construct()
    {
        $modelClass = static::MODEL;
        $this->model = new $modelClass;
    }

    public function getAll(Request $request)
    {
        $objects = $this->model->getAll([
            Model::GET_OPTION_FORMAT => true
        ]);

        return Response::success([
            static::RESOURCE_NAME => $objects
        ]);
    }
}

我保留了 "model class as constant" 方法,但明确引用了 class。

但现在我们正在使用实际对象,我建议更进一步并在不使用 class 常量的间接寻址的情况下实例化它:

class RolesController extends Controller
{
    const RESOURCE_NAME = 'roles';

    public function __construct()
    {
        parent::__construct();
        $this->model = new App\Models\Role();
    }
}


class Controller extends BaseController
{

    protected $model;

    public function __construct()
    {
    }

    public function getAll(Request $request)
    {
        $objects = $this->model->getAll([
            Model::GET_OPTION_FORMAT => true
        ]);

        return Response::success([
            static::RESOURCE_NAME => $objects
        ]);
    }
}

请注意,您不需要将静态方法getAll更改为非静态方法。使用 $object->method 调用静态方法即使在严格模式下也能正常工作(只是反过来不行)。


简答

您也可以使用变量作为 class 名称(不是 属性,如您所试,解析器无法理解):

$class = $this->model;
$objects = $class::getAll([
    Model::GET_OPTION_FORMAT => true
]);

但这只能解决您眼前的编码问题,不能解决结构问题。