扩展程序而不更改源代码。固态PHP OOP

时间:2018-07-28 18:32:16

标签: php solid-principles

比方说我们有几个要素:

1)简单的PHP类

ng: TypeError: Cannot read property 'toUpperCase' of undefined

2)窗口小部件类的接口

as

3)很少有实现Widget接口的类

<?php 
  class page {
    function display() {
      // Display widgets implementing widget interface
    }
 }
?>

牢记SOLID PHP OOP逻辑在实现Widget接口的所有类中自动运行print()函数的正确方法是什么?假设所有文件都已包含在内。

基本上,每当创建实现Widget的新类时,它的响应都应该在页面中打印出来。

也许我背后的所有逻辑都是错误的?

3 个答案:

答案 0 :(得分:1)

我不使用任何配置或数据库的唯一方法就是获取所有声明的类并检查实现Widget接口的类:

这是经过修改的Page

class Page {

    public $widgets = [];

    public function addWidget(Widget $widget)
    {
        $this->widgets[] = $widget;
    }

    public function display()
    {
        // Now you have an array of Widgets you can loop through them
        // And run print()
        foreach ($this->widgets as $widget) {
            $widget->print();
        }
    }
}

然后我们可以获取实现Widget接口的所有类(已加载):

$widgets = array_filter(
    get_declared_classes(),
    function ($className) {
        return in_array('Widget', class_implements($className));
    }
);

然后将它们传递给Page

$page = new Page();
foreach ($widgets as $item) {
    $widget = new $item;
    $page->addWidget($widget);
}

// Now Page has all Widgets we can call display()
$page->display();

但是请注意,get_declared_classes()将返回很多类(在我的PC中为160),因此我们正在遍历所有这些类,并检查每个类是否都实现了Widget接口。

现在,只要您拥有实现Widget接口的类,Page就会使用它。老实说,我不知道是否有更好的方法,所以值得等待其他答案。

答案 1 :(得分:0)

您随时可以使用一点魔术。

假设您将所有小部件都放在一个目录中。您可以通过一些文件系统操作来获取它们,遍历结果,验证它是否是Widet的实例,创建新实例并运行它。

此解决方案有一个很大的好处。您只需编写一次此代码,每个新小部件就会自动包含并运行。这解决了开闭原理:)

但是它也有一些缺点:

  • 您必须使用文件系统,
  • IDE将不知道使用了Widget实现,
  • 这很难理解。

另一种解决方案是拥有WidgetCollection之类的类,该类将了解系统中的所有小部件,并且可以为您提供它们。因此,当您创建一个新的窗口小部件实现时,必须将其添加到集合中,仅此而已:)

干杯。

答案 2 :(得分:0)

我不能真正说出它是否符合SOLID原则,但我可以想到两种方法:

  1. 将窗口小部件存储在目录中,并使用PSR-4自动加载。然后使用文件系统功能扫描目录并创建与文件名相对应的类名实例。 (确保对目录内容具有完全控制权,否则您将被黑!)

    // Totally untested code with no error checking
    foreach (glob(YOUR_BASE_DIR_HERE . '/Widget/*.php') as $file) {
        $className = 'Widget\\' . basename($file, '.php');
        $widget = new $className();
        $widget->print();
    }
    

    这假定不需要配置小部件,因此实例创建可以自动化。

  2. 调整小部件规范,以便每个文件返回正确初始化的实例,并include对其进行初始化(适用相同的警告):

    foreach (glob(YOUR_WIDGETS_DIR_HERE . '/*.php') as $file) {
        $widget = include $file;
        $widget->print();
    }
    

    ...,其中每个包含的文件都以return new Poll();之类的结尾。

    重要的是,包含的文件不要用变量污染全局范围。根据期望的复杂小部件的种类,您可能希望在其他地方有实际的类定义,因此您遵循PSR-1编码标准:文件应声明符号(类,函数,常量等)。 或产生副作用(例如生成输出,更改.ini设置等) 但不应两者都做。