[英]PHP chained class methods merged with other classes
I start with an example. 我从一个例子开始。
Mold class 模具类
<?php
class Mold {
public $current;
function merge($first, $second) {
$this->current = $first . $second;
return $this;
}
function phone() {
$this->current = '<a href="tel:' . $this->current . '">' . $this->current . '</a>';
return $this;
}
function __toString() {
return $this->current;
}
}
function mold() {
return new Mold();
}
In action 在行动
This works as expected. 这按预期工作。
echo mold()->merge('sada', 'asdsa')->phone();
I have one or more classes with methods that wants to be available as well. 我有一个或多个类,它们的方法也希望可以使用。
Plugin class 插件类
class MyPlugin {
function link() {
// Code
}
function currency($number) {
// Code
}
}
class MyPlugin2 {
// Other methods
}
Dream code 梦代码
The exact change of events below may not make any sense. 以下事件的确切变化可能没有任何意义。 Anyway, what I intend to do is the following.
无论如何,我打算做以下事情。
echo mold()->merge('sada', 'asdsa')->currency(45)-link();
mold()
which creates a new instance of the Mold
class. mold()
创建一个新的Mold
类实例。 merge()
which is used from the Mold
class. Mold
类使用的chain merge()
。 currency()
or link()
method does not exist in the Mold
class. Mold
类中不存在currency()
或link()
方法。 Instead they should be loaded from one of the plugins. Mold
class. Mold
类注意。 Technically you could use __call()
for this. 从技术上讲,您可以使用
__call()
。 Your "main" class could contain/track a set of plugin instances and any unknown method call could be looked up and delegated, if available in a plugin. 您的“主”类可以包含/跟踪一组插件实例,并且可以查找和委托任何未知的方法调用(如果在插件中可用)。
I wouldn't recommend this though. 我不会推荐这个。 Fluent APIs are often brittle and can get inconvenient even with one class.
流利的API通常很脆弱,即使只有一类也可能带来不便。 Involving multiple classes in fluent calls might quickly to add up to a confusing mess.
使多个类参与流利的调用可能很快就会造成混乱。 A mess which even IDE can't help you (or another person working with code) with since it has no clue about all the magic happening.
混乱,甚至IDE也无法帮助您(或其他使用代码的人),因为它无法掌握所有发生的魔术。
I would highly recommend to look into alternative patterns for an API like this. 我强烈建议您研究此类API的替代模式。
A concept that you might try to apply is the Composition Over Inheritance . 您可以尝试应用的概念是继承上的合成 。
A solution could be to compose your current Mold
object and pass the two plugins instances so that it could use them on its methods, like so: 一个解决方案可能是组成当前的
Mold
对象并传递两个插件实例,以便它可以在其方法上使用它们,如下所示:
<?php
class Mold {
public $current;
public function __construct(Plugin1 $plugin1, Plugin2 $plugin2) {
$this->plugin1 = $plugin1;
$this->plugin2 = $plugin2;
}
public function merge($first, $second) {
$this->current = $first . $second;
return $this;
}
public function phone() {
$this->current = '<a href="tel:' . $this->current . '">' . $this->current . '</a>';
return $this;
}
public function __toString() {
return $this->current;
}
public function link() {
$this->plugin1->link();
return $this;
}
}
function mold() {
return new Mold(new Plugin1(), new Plugin2());
}
Another solution could be to create a MoldHandler
class of some sort, which has a Mold
object as a property together with the other plugins, which could be used inside of this directly. 另一个解决方案是创建某种
MoldHandler
类,该类将Mold
对象作为属性与其他插件一起使用,可以直接在其中使用。
public class MoldHanlder {
protected $mold;
protected $plugin1;
protected $plugin2;
public function __contruct($mold, $plugin1, $plugin2) {
$this->mold = $mold;
$this->plugin1 = $plugin1;
$this->plugin2 = $plugin2;
}
public function merge() {
$this->mold = $this->mold->merge();
return $this;
}
public function link() {
$foo = $this->plugin1->method();
return $this;
}
...
}
You could also just instantiate the classes inside the construct
, but if you are planning about writing unit tests, dependency injection is the way to go 您也可以只实例化
construct
的类,但是如果您打算编写单元测试,则依赖注入是解决之道
I think that the first approach is way better because you avoid yourself to re-write some code of the Mold class, which is unnecessary 我认为第一种方法更好,因为您避免自己重新编写Mold类的一些代码,这是不必要的
NB this is a really raw solution proposed just to let you better understand the idea I would opt for cheers 注意,这是一个非常原始的解决方案,只是为了让您更好地理解我会选择的想法
Interesting ideas. 有趣的想法。
The one that solves the problem like I had in my mind was to use traits like @vivek_23 suggested in a comment. 解决我所想到的问题的一种方法是使用注释中建议的@ vivek_23之类的特征 。
Here is a complete example of how it works 这是工作原理的完整示例
<?php
// Core methods
class MoldCore {
public $current;
function merge($first, $second) {
$this->current = $first . $second;
return $this;
}
function phone() {
$this->current = '<a href="tel:' . $this->current . '">' . $this->current . '</a>';
return $this;
}
function __toString() {
return $this->current;
}
}
// Plugin 1
trait Plugin1 {
public function yaay() {
$this->current .= ' Plugin1 yaay';
return $this;
}
}
// Plugin 2
trait Plugin2 {
public function hello() {
$this->current = str_replace('Plugin1', 'Modified', $this->current);
return $this;
}
public function world() {
$this->current .= ' Plugin2 world';
return $this;
}
}
// Glue plugins with MoldCore
class Mold extends MoldCore {
use Plugin1, Plugin2;
}
$mold = new Mold();
echo $mold->merge('sada', 'asdsa')->phone()->yaay()->hello();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.