![]() |
1
5
如果您唯一担心的是不包括plugin1会产生错误,那么您可以求助于自动加载,让plugin2自动加载plugin1: 从评论中 PHP Manual on spl_autoload
但是,如果您正在寻找类似traits/mixin的特性,那么答案是否定的。至少 not without patching the core these two 不希望在生产代码中使用的API。 改变对象在运行时的行为的正确方法是使用 Decorators
Strategy 模式:
看到了吗 http://sourcemaking.com/design_patterns 最常见的模式。 下面是一个如何使用decorator创建插件的示例。假设,我们有一个游戏,其中一些非玩家角色在虚拟空间中走动,时不时地和主人公打招呼。他们现在只做这些。不过,我们希望它们的问候方式有所不同,这就是为什么在这个场景中我们需要插件/装饰器的原因。 首先我们 create an interface 它定义了任何能够问候的对象应该具有的一些方法。我们不关心在特定对象上调用这些方法时它会做什么。我们只想确保这些方法可用,并使用明确定义的输入调用它们:
现在让我们构建非玩家角色类,实现这个接口
我想那是相当困难的。Dude类只是从接口定义了两个方法。调用greet()时,它将获取存储在greeting中的字符串,并将其前置到传递给greet方法的参数。setGreeting方法允许我们在运行时更改问候语。 现在来看看插件。我们将创建一个抽象的GreetPlugin类来包含 shared boilerplate code ,只是因为我们不想在实际的插件中复制代码。抽象插件类将实现GreetInterface,因此我们可以确保所有子类也实现该接口。 既然Dude已经实现了这个接口,我们可以让插件扩展Dude,但这在概念上是错误的,因为扩展会创建一个 关系,但插件不是花花公子。
TypeHint 确保班级履行合同。这是必需的,因为正如您在代码中看到的,我们的插件将需要调用通过构造函数传递的类的接口中的方法。如果我们从“花花公子”扩展到“花花公子”,我们现在就可以把花花公子包装成花花公子了,这有点奇怪。不这么做的另一个原因。 现在开始第一个插件。我们想让我们的一些人说一个花哨的法国口音,这意味着他们使用ccnt各地,但不能发出一个正确的h。 免责声明:是的,我知道那是陈词滥调。请接受我的例子
这样我们只重写构造函数,因为greet方法应该只返回它将返回的任何内容。所以我们对传递给这个插件的对象调用setGreeting方法。因为对象必须实现GreetInterface,所以我们可以确定这是可行的。 有了两个插件,我们觉得我们有足够的变化。现在我们只需要一个方便的方法来创造男人。为此,我们创建了这样一个小类:
注:我总是混淆建设者和抽象工厂,所以如果上面是一个工厂,那么它是一个工厂。查看我前面给出的设计模式链接;) 这个生成器所做的一切,就是创建一个普通的dude,然后用我们告诉它使用的插件包装/装饰它,然后返回它。因为构建器不封装自己的状态,所以我们使构建方法是静态的。 对于本例,我假设您使用了我在顶部给出的自动加载代码。如果没有,可以在foreach循环中包含插件文件。只在需要的时候懒洋洋地加载它们会使加载时间缩短几微秒,把它们都放在上面。希望这也能解释我在各种评论中的意思,当时我认为行为不应该由文件包含控制。文件包含只是必要的。不能使用对PHP不了解的类。但是这个类的实际使用是由我们的代码单独控制的,通过将插件名传递给build方法。
这实际上与执行以下操作相同:
只需两个插件,我们就可以创建三种类型的花花公子。让他们问候你:
我们现在可以创建额外的插件来装饰我们的基本类。如果出于某种原因,你决定你的游戏也应该有会说话的马或车,你也可以创建一个类车或马,让它实现问候接口,并为它们添加一个生成器。然后可以重用这些插件来创建法国随和的汽车或马。 |
![]() |
2
6
你误用了“插件”这个词。插件通常是一个扩展或改变系统基本功能的代码包 实际的 PHP插件(在PHP世界中称为 你会写C或C++。 这里所描述的只是将类或类树包含到当前执行中以供使用。在那里 是 一种“自动”将它们引入当前执行上下文的方法,这是通过 autoload system . 如果在您阅读了有关自动加载的文档之后,仍然不确定如何继续,请在此处发表评论,我将帮助您。 编辑
确切地
你在追求什么。当你执行
|
![]() |
3
2
核心功能可以通过
如果你能解释一下你的计划,我们能提供一个更好的答案吗? |
![]() |
4
0
您的代码正在中断,因为plugin2扩展了plugin1,而您没有包含plugin1类。为什么不让类plugin2扩展核心呢?这似乎就是你想要的。 |