Pek*_*ica 114 php oop design-patterns
在基于PHP的面向对象项目中,如何组织和管理辅助对象,如数据库引擎,用户通知,错误处理等?
假设我有一个大的PHP CMS.CMS由各种类别组织.几个例子:
等等
我正在处理永恒的问题,如何最好地使这些对象可以访问需要它的系统的每个部分.
很多年前,我的第一个应用程序是拥有一个包含这些类的初始化实例的$ application全局.
global $application;
$application->messageHandler->addMessage("Item successfully inserted");
Run Code Online (Sandbox Code Playgroud)
然后我切换到Singleton模式和工厂函数:
$mh =&factory("messageHandler");
$mh->addMessage("Item successfully inserted");
Run Code Online (Sandbox Code Playgroud)
但我对此也不满意.单元测试和封装对我来说变得越来越重要,在我的理解中,全局/单例背后的逻辑破坏了OOP的基本思想.
那么当然有可能给每个对象提供它需要的辅助对象的许多指针,可能是最干净,资源节省和测试友好的方式,但我对这长期可维护性有疑问.
我研究过的大多数PHP框架都使用单例模式或访问初始化对象的函数.这两种方法都不错,但正如我所说的那样,我对它们都不满意.
我想扩大我对这里存在的常见模式的看法.我找实例,更多的想法和指针向资源从讨论这个长期的,真实世界的视角.
另外,我很想知道这个问题的专门,利基或简单的奇怪方法.
koe*_*oen 68
我会避免Flavius提出的Singleton方法.有许多理由可以避免这种方法.它违反了良好的OOP原则.谷歌测试博客有一些关于Singleton的好文章以及如何避免它:
http://googletesting.blogspot.com/2008/08/by-miko-hevery-so-you-join-new-project.html http://googletesting.blogspot.com/2008/05/tott-using-dependancy -injection-to.html http://googletesting.blogspot.com/2008/08/where-have-all-singletons-gone.html
服务提供商
http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html
依赖注入
http://en.wikipedia.org/wiki/Dependency_injection
和一个PHP的解释:
http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection
这是一篇关于这些替代品的好文章:
http://martinfowler.com/articles/injection.html
我相信你应该问一下构造函数中需要什么才能使对象起作用:new YourObject($dependencyA, $dependencyB);
您可以手动提供所需的对象(依赖项)($application = new Application(new MessageHandler()).但您也可以使用DI框架(维基百科页面提供了PHP DI框架的链接).
重要的是,您只传入实际使用的内容(调用操作),而不是传递给其他对象的内容,因为它们需要它.这是"叔叔鲍勃"(Robert Martin)最近发表的一篇文章,讨论了手册DI与使用框架.
关于Flavius解决方案的更多想法.我不希望这篇文章成为反帖,但我认为重要的是要看到为什么依赖注入至少对我来说比全局变量更好.
即使它不是一个'真正的' 单身人士实施,我仍然认为弗拉维乌斯错了.全球状态不好.请注意,此类解决方案也使用难以测试的静态方法.
我知道很多人都这样做,批准并使用它.但阅读Misko Heverys的博客文章(谷歌可测性专家),重新阅读并慢慢消化他所说的内容确实改变了我看待设计的方式.
如果您希望能够测试应用程序,则需要采用不同的方法来设计应用程序.当你进行测试优先编程时,你会遇到这样的问题:'接下来我想在这段代码中实现日志记录; 让我们首先编写一个记录基本消息的测试,然后进行测试,强制您编写并使用无法替换的全局记录器.
我仍在努力处理从博客中获得的所有信息,并不总是很容易实现,而且我有很多问题.但是在我掌握了Misko Hevery所说的内容之后,我无法回到之前所做的事情(是的,全球州和Singletons(大S)):-)
Fla*_*ius 16
class Application {
protected static $_singletonFoo=NULL;
public static function foo() {
if(NULL === self::$_singletonFoo) {
self::$_singletonFoo = new Foo;
}
return self::$_singletonFoo;
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我这样做的方式.它按需创建对象:
Application::foo()->bar();
Run Code Online (Sandbox Code Playgroud)
这就是我这样做的方式,它尊重OOP原则,它比现在你做的更少代码,并且只有在代码第一次需要它时才创建对象.
注意:我所呈现的甚至不是真正的单例模式.通过将构造函数(Foo :: __ constructor())定义为private,单例将只允许自身的一个实例.它只是一个可用于所有"应用程序"实例的"全局"变量.这就是为什么我认为它的使用是有效的,因为它不会忽视良好的OOP原则.当然,就像世界上任何事物一样,这种"模式"也不应该被滥用!
我已经看到它在许多PHP框架中使用,Zend Framework和其中的Yii.你应该使用一个框架.我不打算告诉你哪一个.
附录 对于那些担心TDD的人来说,你仍然可以通过依赖注入来弥补它.它可能看起来像这样:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
有足够的改进空间.它只是一个PoC,用你的想象力.
为什么这样?好吧,大多数情况下,应用程序不会进行单元测试,它实际上会运行,希望在生产环境中运行.PHP的优势在于它的速度.PHP不是,也永远不会像Java一样"干净的OOP语言".
在一个应用程序中,最多只有一个Application类,每个Helper只有一个实例(根据上面的延迟加载).当然,单身人士很糟糕,但又一次,只有他们不坚持现实世界.在我的例子中,他们这样做.
刻板的"规则",如"单身人士是坏人"是邪恶的根源,他们是懒惰的人不愿意为自己思考.
是的,我知道,从技术上讲,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();
Run Code Online (Sandbox Code Playgroud)
Tho*_*mas 15
我喜欢依赖注入的概念:
"依赖注入是组件通过其构造函数,方法或直接进入字段的依赖关系.(来自Pico Container网站)"
Fabien Potencier撰写了一系列关于依赖注入的非常好的文章以及使用它们的必要性.他还提供了一个很好的小型依赖注入容器,名为Pimple,我非常想使用它(github上的更多信息).
如上所述,我不喜欢单身人士的使用.关于为什么Singletons不是好设计的一个很好的总结可以在Steve Yegge的博客中找到.
最好的方法是为这些资源提供某种容器.实现此容器的一些最常用方法:
不推荐,因为它很难测试并暗示全局状态.(Singletonitis)
消除单一炎症,我也不建议使用注册表,因为它也是一种单身人士.(难以进行单元测试)
可惜,PHP中没有多重继承,因此这限制了所有链.
这是一种更好的方法,但是一个更大的主题.
最简单的方法是使用构造函数或setter注入(使用setter或类构造函数传递依赖项对象).
您可以滚动自己的依赖注入器,或者使用一些依赖注入框架,例如.Yadif
您可以初始化应用程序引导程序(充当容器)中的每个资源,并在访问引导程序对象的应用程序中的任何位置访问它们.
这是Zend Framework 1.x中实现的方法
一种静态对象,仅在需要时加载(创建)所需的资源.这是一种非常聪明的方法.您可能会看到它的实际效果,例如实现Symfony的依赖注入组件
在应用程序的任何地方都不总是需要资源.有时你只需要它们,例如在控制器中(MV C).然后你可以只在那里注入资源.
常见的方法是使用docblock注释添加注入元数据.
在这里看到我的方法:
如何在Zend Framework中使用依赖注入?- 堆栈溢出
最后,我想在这里添加一个非常重要的注释 - 缓存.
通常,尽管您选择了技术,但您应该考虑如何缓存资源.缓存将是资源本身.
应用程序可能非常大,并且在每次请求时加载所有资源非常昂贵.有很多方法,包括这个appserver-in-php - Google Code上的Project Hosting.
| 归档时间: |
|
| 查看次数: |
12195 次 |
| 最近记录: |