繁体   English   中英

PHP链式类方法与其他类合并

[英]PHP chained class methods merged with other classes

我从一个例子开始。

模具类

<?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();
}

在行动

这按预期工作。

echo mold()->merge('sada', 'asdsa')->phone();

问题

我有一个或多个类,它们的方法也希望可以使用。

插件类

class MyPlugin {
  function link() {
    // Code
  }

  function currency($number) {
    // Code
  }
}
class MyPlugin2 {
  // Other methods
}

梦代码

以下事件的确切变化可能没有任何意义。 无论如何,我打算做以下事情。

echo mold()->merge('sada', 'asdsa')->currency(45)-link();
  • 调用mold()创建一个新的Mold类实例。
  • Mold类使用的chain merge()
  • Mold类中不存在currency()link()方法。 而是应从其中一个插件加载它们。

结论

  • 我知道我可以扩展一个类,但是它不能真正解决问题,因为可以有多个插件类。
  • 我知道我可以创建插件类的实例,但是它们需要以某种方式由Mold类注意。
  • 将方法追加到类以及合并类都放在脑海中。

从技术上讲,您可以使用__call() 您的“主”类可以包含/跟踪一组插件实例,并且可以查找和委托任何未知的方法调用(如果在插件中可用)。

我不会推荐这个。 流利的API通常很脆弱,即使只有类也可能带来不便。 使多个类参与流利的调用可能很快就会造成混乱。 混乱,甚至IDE也无法帮助您(或其他使用代码的人),因为它无法掌握所有发生的魔术。

我强烈建议您研究此类API的替代模式。

您可以尝试应用的概念是继承上的合成

一个解决方案可能是组成当前的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());
}

另一个解决方案是创建某种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;
    }

    ...
}

您也可以只实例化construct的类,但是如果您打算编写单元测试,则依赖注入是解决之道

我认为第一种方法更好,因为您避免自己重新编写Mold类的一些代码,这是不必要的

注意,这是一个非常原始的解决方案,只是为了让您更好地理解我会选择的想法

有趣的想法。

解决我所想到的问题的一种方法是使用注释中建议的@ vivek_23之类的特征

这是工作原理的完整示例

<?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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM