在 Laravel 中扩展多个类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21957036/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 09:04:39  来源:igfitidea点击:

Extending Multiple Classes In Laravel

phplaravelextendsrevisionable

提问by Aman Virk

I am stuck as Php natively does not allow extending multiple classes, i am using laravel models to interact with data and want to use 2 different packages to extend it's functionality.

我被卡住了,因为 PHP 本身不允许扩展多个类,我使用 laravel 模型与数据交互,并希望使用 2 个不同的包来扩展它的功能。

I am trying to use Ardenta validator and Revisionablewhich maintains update history but i am not sure how to extend these 2 classes within my models.

我正在尝试使用Ardent验证器和Revisionable来维护更新历史记录,但我不确定如何在我的模型中扩展这 2 个类。

Any help will be appreciated.

任何帮助将不胜感激。

回答by Antonio Carlos Ribeiro

As you know, PHP doesn't support multiple inheritance and unfortunately, this is a PHP deficiency and a problem created by ardent and revisionable package developers. Take Sentry as an example, you can use whatever implementation of Eloquent you want, you just have set the one you need in config.php. Laravel unfortunately has its hands tied, since it is the base class of all those packages. In my opinion.

如您所知,PHP 不支持多重继承,不幸的是,这是 PHP 的一个缺陷,也是由热心且可修改的包开发人员创建的问题。以 Sentry 为例,你可以使用任何你想要的 Eloquent 实现,你只需要在 config.php 中设置你需要的。不幸的是,Laravel 束手无策,因为它是所有这些包的基类。在我看来。

So you have some options:

所以你有一些选择:

1) File an issue on both packages git repositories and hope that one of them changes to support inheritance not only from \Eloquent, but any of the user's classes, extending Eloquent Model abstract class.

1) 在两个包 git 存储库上提交问题,并希望其中一个更改以支持不仅从 \Eloquent 继承,而且支持从任何用户的类继承,扩展 Eloquent 模型抽象类。

You can even change the code of one of those packages and send a pull request to the repository. If it's a good change you probably will see it happening.

您甚至可以更改其中一个包的代码并向存储库发送拉取请求。如果这是一个好的改变,你可能会看到它发生。

2) Use the repository pattern, by creating a class extended from Eloquent, having both of your packages as dependency and, inside it, calling whatever you need from those packages. This will not be a piece of cake, because Eloquent is a complex class and, if you use __call(), you'll have to map all methods you need to forward to your packages, so you don't risk breaking Eloquent's own dynamic calls:

2) 使用存储库模式,通过创建一个从 Eloquent 扩展的类,将两个包作为依赖项,并在其中从这些包中调用您需要的任何内容。这不是小菜一碟,因为 Eloquent 是一个复杂的类,如果你使用__call(),你必须映射所有你需要转发到你的包的方法,所以你不会冒险破坏 Eloquent 自己的动态调用:

use Ardent;
use Revisionable;

class User extends Eloquent {

    private $ardent;

    privave $revisionable;

    public function __construct(Ardent $ardent, Revisionable $revisionable)
    {
        $this->ardent = $ardent;

        $this->revisionable = $revisionable;
    }

    public function doWhatever() 
    {
        return $this->ardent->do();
    }

    public function __call($name, $arguments)
    {
        if($this->isArdentMethod($name))
        {
            return call_user_func_array(array($this->ardent,$name), $arguments);
        }
        else
        if($this->isRevisionableMethod($name))
        {
            return call_user_func_array(array($this->revisionable,$name), $arguments);
        }
        else
        {
            return parent::__call($name, $arguments);
        }
    }
}

Note that this call

注意这个调用

return parent::__call($name, $arguments);

Ensures that all of your calls will be redirected to your Eloquent class, if they are not meant to be executed by one of the others.

确保您的所有调用都将重定向到您的 Eloquent 类,如果它们不打算由其他调用之一执行。

As a matter of fact you could even choose one of those, like Ardent as your main class:

事实上,您甚至可以选择其中之一,例如 Ardent 作为您的主要课程:

class User extends Ardent {}

And just have revisionable as a dependency:

并且只需将可修订作为依赖项:

public function __construct(Revisionable $revisionable)

And then forward just revisionable calls to the injected dependency. Because, in the end, those classes are all Eloquent and you can have many Eloquent models pointing to the same tables.

然后将可修改的调用转发给注入的依赖项。因为,最终,这些类都是 Eloquent 的,您可以有许多 Eloquent 模型指向相同的表。

If you look at Revisionable source code you'll that the only call you really have to think of is save(), because it overrides it from Eloquent, all the other you can just call Ardent's.

如果您查看 Revisionable 源代码,您会发现您真正需要考虑的唯一调用是save(),因为它从 Eloquent 覆盖了它,所有其他调用都可以调用 Ardent。

I know it sounds like a bit too much, but it's doable.

我知道这听起来有点过分,但它是可行的。

回答by duellsy

I've been putting a lot of work into making Revisionable a trait recently.

我最近做了很多工作来使 Revisionable 成为一个特性。

So you'll be able to useit, like this:

所以你将能够use做到,就像这样:

class User extends Ardent {
    use \Venturecraft\Revisionable\RevisionableTrait;
}

It's currently in the dev branch, but I'd love some help testing before it gets merged to maser:

它目前在 dev 分支中,但我希望在它合并到 maser 之前进行一些帮助测试:

https://github.com/VentureCraft/revisionable/issues/36

https://github.com/VentureCraft/revisionable/issues/36

[EDIT]This is now in the master branch, and available for public use.

[编辑]现在在 master 分支中,可供公众使用。

回答by George Brighton

As you say, PHP doesn't support multiple inheritance, so you don't have many options. As ugly as it is, you may have to resort to something like this, which uses the __call()magic method.

如您所说,PHP 不支持多重继承,因此您没有太多选择。由于丑陋,因为它是,你可能不得不求助于像这样,它使用了__call()魔术方法。