Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 在PHP项目中,存在哪些模式来存储、访问和组织帮助对象?_Design Patterns_Oop_Php - Fatal编程技术网

Design patterns 在PHP项目中,存在哪些模式来存储、访问和组织帮助对象?

Design patterns 在PHP项目中,存在哪些模式来存储、访问和组织帮助对象?,design-patterns,oop,php,Design Patterns,Oop,Php,在基于PHP的面向对象项目中,如何组织和管理助手对象,如数据库引擎、用户通知、错误处理等 假设我有一个大的PHP CMS。 CMS分为不同的班级。举几个例子: 数据库对象 用户管理 用于创建/修改/删除项目的API 向最终用户显示消息的消息对象 一个上下文处理程序,可以将您带到正确的页面 显示按钮的导航栏类 日志对象 可能是自定义错误处理 等等 我正在处理一个永恒的问题,如何最好地使系统中需要这些对象的每个部分都可以访问这些对象 多年前,我的第一个建议是拥有一个$applicationglo

在基于PHP的面向对象项目中,如何组织和管理助手对象,如数据库引擎、用户通知、错误处理等

假设我有一个大的PHP CMS。 CMS分为不同的班级。举几个例子:

  • 数据库对象
  • 用户管理
  • 用于创建/修改/删除项目的API
  • 向最终用户显示消息的消息对象
  • 一个上下文处理程序,可以将您带到正确的页面
  • 显示按钮的导航栏类
  • 日志对象
  • 可能是自定义错误处理
等等

我正在处理一个永恒的问题,如何最好地使系统中需要这些对象的每个部分都可以访问这些对象

多年前,我的第一个建议是拥有一个$applicationglobal,其中包含这些类的初始化实例

global $application;
$application->messageHandler->addMessage("Item successfully inserted");
然后我切换到单例模式和工厂函数:

$mh =&factory("messageHandler");
$mh->addMessage("Item successfully inserted");
但我对此也不满意。单元测试和封装对我来说越来越重要,在我的理解中,globals/singleton背后的逻辑破坏了OOP的基本思想

然后,当然有可能给每个对象提供一些指向它所需的助手对象的指针,这可能是最干净、最节省资源和测试友好的方式,但我怀疑从长远来看,这种方式的可维护性

我研究过的大多数PHP框架要么使用单例模式,要么使用访问初始化对象的函数。这两种方法都很好,但正如我所说,我对两者都不满意

我想拓宽我的视野,了解这里存在哪些共同模式。我正在寻找从长期现实世界角度讨论这一问题的示例、其他想法和参考资料

另外,我很想听听关于这个问题的专业化、利基化或普通怪异的方法

class Application {
    protected static $_singletonFoo=NULL;

    public static function foo() {
        if(NULL === self::$_singletonFoo) {
            self::$_singletonFoo = new Foo;
        }
        return self::$_singletonFoo;
    }

}
我会这样做的。它根据需要创建对象:

Application::foo()->bar();
这就是我的工作方式,它尊重OOP原则,它的代码比你现在的工作方式少,并且只有当代码第一次需要它时才创建对象

注意:我所介绍的甚至不是真正的单例模式。通过将构造函数(Foo::u constructor())定义为private,单例将只允许自身的一个实例。它只是一个“全局”变量,可用于所有“应用程序”实例。这就是为什么我认为它的使用是有效的,因为它没有忽视良好的OOP原则。当然,与世界上任何事物一样,这种“模式”也不应该被过度使用

我已经在许多PHP框架中看到了这一点,Zend框架和Yii就是其中之一。你应该使用一个框架。我不会告诉你是哪一个

附录 对于你们当中担心的人,你们仍然可以编一些线路来注入依赖关系。它可能是这样的:

class Application {
        protected static $_singletonFoo=NULL;
        protected static $_helperName = 'Foo';

        public static function setDefaultHelperName($helperName='Foo') {
                if(is_string($helperName)) {
                        self::$_helperName = $helperName;
                }
                elseif(is_object($helperName)) {
                        self::$_singletonFoo = $helperName;
                }
                else {
                        return FALSE;
                }
                return TRUE;
        }
        public static function foo() {
                if(NULL === self::$_singletonFoo) {
                        self::$_singletonFoo = new self::$_helperName;
                }
                return self::$_singletonFoo;
        }
}
有足够的改进空间。这只是一个PoC,发挥你的想象力

为什么会这样?大多数情况下,应用程序不会进行单元测试,而是实际运行,希望在生产环境中运行。PHP的优势在于它的速度。PHP不是,也永远不会像Java一样成为“干净的OOP语言”

在一个应用程序中,最多只有一个应用程序类和它的每个助手的一个实例(根据上面的延迟加载)。当然,单身是不好的,但是,再说一次,除非他们不遵守现实世界。在我的例子中,他们确实如此

像“单身是坏的”这样刻板的“规则”是罪恶的根源,它们是为那些不愿为自己着想的懒人制定的

是的,我知道,从技术上讲,PHP宣言很糟糕。然而,它是一种成功的语言,以其粗俗的方式

补遗 一种功能样式:

function app($class) {
    static $refs = array();

    //> Dependency injection in case of unit test
    if (is_object($class)) {
        $refs[get_class($class)] = $class;
        $class = get_class($class);
    }

    if (!isset($refs[$class]))
        $refs[$class] = new $class();

    return $refs[$class];
}

//> usage: app('Logger')->doWhatever();

我会避免弗拉维乌斯建议的单例方法。有许多理由避免这种做法。它违反了良好的OOP原则。谷歌测试博客上有一些关于单例和如何避免单例的好文章:

选择
  • 服务提供者

  • 依赖注入

    还有一个php解释:

  • 这是一篇关于这些备选方案的好文章:

    实现依赖注入(DI):
    • 我相信你应该:
      新建你的对象($dependencyA,$dependencyB)

    • 您可以手动提供所需的对象(依赖项)(
      $application=newapplication(newmessagehandler()
      )。但您也可以使用DI框架(wikipedia页面提供)

      重要的是,你只传递你实际使用的东西(调用一个动作),而不是因为其他对象需要而传递给他们的东西

    关于Flavius的解决方案还有一些想法。我不想让这篇文章成为一篇反对文章,但我认为重要的是要了解为什么依赖注入,至少对我来说,比全局注入更好

    即使它不是一个“真正的”实现,我仍然认为Flavius弄错了。注意,这样的解决方案也会使用

    我知道很多人都这么做,批准并使用它。但是阅读Misko Heverys的博客文章(),重新阅读,慢慢消化他所说的,确实改变了我对设计的看法

    如果您希望能够测试您的应用程序,您需要采用不同的方法来设计您的应用程序。当您执行test first编程时,您将遇到以下困难:“接下来,我想在这段代码中实现日志记录;让我们先编写一个记录基本消息的测试”,然后编写一个强制您编写和使用无法替换的全局记录器

    我仍然保留着从那得到的所有信息
    $object = load::singleton('classname');
    //or
    $object = classname::instance(); // which sets self::$instance = $this
    
    $object = new Class();
    
    A('Users')->getCurrentUser();