In a PHP project, what patterns exist to store, access and organize helper objects?

12,972

Solution 1

I would avoid the Singleton approach suggested by Flavius. There are numerous reasons to avoid this approach. It violates good OOP principles. The google testing blog has some good articles on the Singleton and how to avoid it:

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

Alternatives

  1. a service provider

    http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html

  2. dependency injection

    http://en.wikipedia.org/wiki/Dependency_injection

    and a php explanation:

    http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection

This is a good article about these alternatives:

http://martinfowler.com/articles/injection.html

Implementing dependency injection (DI):

Some more thoughts on Flavius's solution. I don't want this post to be an anti-post but I think it's important to see why dependency injection is, at least for me, better than globals.

Even though it is not a 'true' Singleton implementation, I still think Flavius got it wrong. Global state is bad. Note that such solutions also use difficult to test static methods.

I know a lot of people do it, approve it and use it. But reading Misko Heverys blog articles (a google testability expert), rereading it and slowly digesting what he says did alter the way I see design a lot.

If you want to be able to test you application, you'll need to adopt a different approach to designing your application. When you do test-first programming, you'll have difficulty with things like this: 'next I want to implement logging in this piece of code; let's write a test first that logs a basic message' and then come up with a test that forces you to write and use a global logger that can't be replaced.

I am still struggling with all the information I got from that blog, and it's not always easy to implement, and I have many questions. But there's no way I can go back to what I did before (yes, global state and Singletons (big S)) after I grasped what Misko Hevery was saying :-)

Solution 2

class Application {
    protected static $_singletonFoo=NULL;

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

}

This is the way I'd do it. It creates the object on demand:

Application::foo()->bar();

It's the way I am doing it, it respects OOP principles, it's less code than how you're doing it right now,and the object is created only when the code needs it for the first time.

Note: what I've presented is not even a real singleton pattern. A singleton would allow only one instance of itself by defining the constructor (Foo::__constructor()) as private. It is only a "global" variable available to all "Application" instances. That's why I think its use is valid as it does NOT disregard good OOP principles. Of course, as anything in the world, this "pattern" should not be overused either!

I've seen this being used in many PHP frameworks, Zend Framework and Yii among them. And you should use a framework. I'm not going to tell you which one.

Addendum For the ones among you worrying about TDD, you can still make up some wiring to dependency-inject it. It could look like this:

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;
        }
}

There's enough room for improvement. It's just a PoC, use your imagination.

Why do it like that? Well, most of the time the application won't be unit-tested, it will actually be run, hopefully in a production environment. The strength of PHP is its speed. PHP is NOT and never will be a "clean OOP language", like Java.

Within an application, there is only one Application class and only one instance of each of its helpers, at most (as per lazy loading as above). Sure, singletons are bad, but then again, only if they don't adhere to the real world. In my example, they do.

Stereotyped "rules" like "singletons are bad" are the source of evil, they're for lazy people not willing to think for themselves.

Yeah, I know, the PHP manifesto is BAD, technically speaking. Yet it's a successful language, in its hackish way.

Addendum

One function style:

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

Solution 3

I like the concept of Dependency Injection:

"Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields. (From Pico Container Website)"

Fabien Potencier wrote a really nice series of articles about Dependency Injection and the need to use them. He also offers a nice and small Dependency Injection Container named Pimple which I really much like to use (more info on github).

As stated above, I don't like the use of Singletons. A good summary on why Singletons aren't good design can be found here in Steve Yegge's blog.

Solution 4

The best approach is to have some kind of a container for those resources. Some of the most common ways to implement this container:

Singleton

Not recommended because it is hard to test and implies a global state. (Singletonitis)

Registry

Eliminates singletonitis, bug I'd not recommend registry too, because it is a kind of singleton too. (Hard to unit test)

Inheritance

Pity, there is no multiple inheritance in PHP, so this limits all to the chain.

Dependency injection

This is a better approach, but a bigger topic.

Traditional

The simplest way of doing this is using constructor or setter injection (pass dependency object using setter or in the class constructor).

Frameworks

You may roll your own dependency injector, or using some of the dependency injection frameworks, eg. Yadif

Application resource

You may initialize each of your resources in the application bootstrap (which acts as a container), and access them anywhere in app accessing the bootstrap object.

This is the approach implemented in Zend Framework 1.x

Resource loader

A kind of a static object which loads (creates) needed resource only when needed. This is a very smart approach. You may see it in action e.g. implementing Symfony's Dependency Injection component

Injection to specific layer

The resources are not always needed anywhere in the application. Sometimes you just need them e.g. in the controllers (MV C ). Then you may inject the resources only there.

The common approach to this is using docblock comments to add injection metadata.

See my approach to this here:

How to use dependency injection in Zend Framework? - Stack Overflow

In the end, I'd like to add a note about very important thing here - caching.
In general, despite the technique you choose, you should think how the resources will be cached. The cache will be the resource itself.

The applications can be very big, and loading all resources upon each request is very expensive. There are many approaches, including this appserver-in-php - Project Hosting on Google Code.

Solution 5

If you want to make objects globally available, the registry pattern could be interesting for you. For inspiration, have a look at Zend Registry.

So also the Registry vs. Singleton question.

Share:
12,972

Related videos on Youtube

Pekka
Author by

Pekka

Self-employed web developer and graphic designer. After-hours artist. Working from an old off-the-grid house in the Canary Islands. Not doing much here any more because the Stack Overflow I wish to build and participate in is no longer supported and the company running it has started going down a path of incomprehensible, increasingly outright evil actions. E-Mail: first name at gmx dot de

Updated on April 15, 2022

Comments

  • Pekka
    Pekka about 2 years

    How do you organize and manage your helper objects like the database engine, user notification, error handling and so on in a PHP based, object oriented project?

    Say I have a large PHP CMS. The CMS is organized in various classes. A few examples:

    • the database object
    • user management
    • an API to create/modify/delete items
    • a messaging object to display messages to the end user
    • a context handler that takes you to the right page
    • a navigation bar class that shows buttons
    • a logging object
    • possibly, custom error handling

    etc.

    I am dealing with the eternal question, how to best make these objects accessible to each part of the system that needs it.

    my first apporach, many years ago was to have a $application global that contained initialized instances of these classes.

    global $application;
    $application->messageHandler->addMessage("Item successfully inserted");
    

    I then changed over to the Singleton pattern and a factory function:

    $mh =&factory("messageHandler");
    $mh->addMessage("Item successfully inserted");
    

    but I'm not happy with that either. Unit tests and encapsulation become more and more important to me, and in my understanding the logic behind globals/singletons destroys the basic idea of OOP.

    Then there is of course the possibility of giving each object a number of pointers to the helper objects it needs, probably the very cleanest, resource-saving and testing-friendly way but I have doubts about the maintainability of this in the long run.

    Most PHP frameworks I have looked into use either the singleton pattern, or functions that access the initialized objects. Both fine approaches, but as I said I'm happy with neither.

    I would like to broaden my horizon on what common patterns exist here. I am looking for examples, additional ideas and pointers towards resources that discuss this from a long-term, real-world perspective.

    Also, I'm interested to hear about specialized, niche or plain weird approaches to the issue.

    • philfreo
      philfreo over 14 years
      I just asked an extremely similar question that also had a bounty. You may appreciate some answers there: stackoverflow.com/questions/1967548/…
    • ryeguy
      ryeguy over 14 years
      Just a head's up, returning a new object by reference - like $mh=&factory("messageHandler"); is pointless and does not yield any performance benefit. In addition, this is deprecated in 5.3.
  • koen
    koen over 14 years
    I downvoted the answer because I believe suggesting the singleton pattern to handle the problem goes against solid OOP principles.
  • Einstein
    Einstein over 14 years
    @koen: what you're saying is true, generally speaking, BUT as far as I understood his problem, he's talking about helpers for the application, and within an application there's only one ... uhm, application.
  • Einstein
    Einstein over 14 years
    Note: what I've presented is not even a real singleton pattern. A singleton would allow only one instance of a class by defining the constructor as private. It is only a "global" variable available to all "Application" instances. That's why I think its valid does NOT disregard good OOP principles. Of course, as anything in the world, this "pattern" should not be overused either.
  • Chance
    Chance over 14 years
    +1 for DI. Although I don't use it as much as I'd like to, it's been very helpful in whatever small quantities I did use it on.
  • Alix Axel
    Alix Axel over 14 years
    @koen: Care to give a PHP example of a DI / SP implementation in PHP? Maybe @Flavius code implemented using the alternative patterns you suggested?
  • Thomas Müller
    Thomas Müller over 14 years
    Added a link to DI implementation and container in my answer.
  • Juraj Blahunka
    Juraj Blahunka over 14 years
    I like the implementation through Closures in PHP, very interesting reading
  • Thomas Müller
    Thomas Müller over 14 years
    Me too an he has some other need stuff regarding closures on his site: fabien.potencier.org/article/17/…
  • Juraj Blahunka
    Juraj Blahunka over 14 years
    let's hope, that mainstream webhouses will migrate to PHP 5.3 soon, as it is still not common to see a full featured php 5.3 server
  • Thomas Müller
    Thomas Müller over 14 years
    They will have to, when more and more projects require PHP 5.3 like Zend Framework 2.0 will framework.zend.com/wiki/display/ZFDEV2/…
  • JasonDavis
    JasonDavis over 14 years
    I am reading over all this now but I havent read it all yet, I would like to ask, is would a dependacy injection framework basicly be a Registry?
  • Thomas Müller
    Thomas Müller over 14 years
    If you don't want to use Zend Framework, here is a nice implementation of the registry pattern for PHP5: phpbar.de/w/Registry
  • Thomas Müller
    Thomas Müller over 14 years
    No, not really. But a Dependency Injection Container may servce as a registry, too. Just read the links I have posted in my answer. The conpect of DI is explained really practically.
  • just somebody
    just somebody over 14 years
    -1 from me too. It may only be one half of the Singleton DP, but it's the ugly one: "provide global access to it".
  • Juraj Blahunka
    Juraj Blahunka over 14 years
    Dependency injection was also accepted answer on question about decupling from GOD object: stackoverflow.com/questions/1580210/… with a very nice example
  • ROBY HERNAN RUBIANO
    ROBY HERNAN RUBIANO over 14 years
    This does indeed make his existing approach much cleaner.
  • Alix Axel
    Alix Axel over 14 years
    @Daniel: Agreed, +1 this approach compared to DI seems much more practical and easy to use.
  • Xeoncross
    Xeoncross over 14 years
    This is just asking for memory waste with forgotten objects. However, it is a nice way to implement singleton if you are careful.
  • Einstein
    Einstein over 14 years
    Any technique involving objects is vulnerable to that programming mistake, including dependency injection. The only way around it is using static methods/functions as helpers.
  • Morfildur
    Morfildur over 14 years
    I prefer a typed Registry Pattern, like Registry::GetDatabase("master"); Registry::GetSession($user->SessionKey()); Registry::GetConfig("local"); [...] and defining an interface for each type. This way you make sure you don't accidently overwrite a key used for something different (i.e. you might have a "master Database" and a "master Config". By using Interfaces you make sure that only valid objects are used. Ofc this could also be implemented by using multiple Registry classes but imho a single one is simpler and easier to use but still has the advantages.
  • Pekka
    Pekka over 14 years
    Thanks gcb, but the loading of classes is not my concern, my question is of a more architectural nature.
  • sunwukung
    sunwukung about 14 years
    Personally, I think this method is a juicy workaround for the singleton problem. There are instances where you need a unique object, and you don't want to keep passing references to that object around the system. Nice!
  • Einstein
    Einstein about 14 years
    What "the other guys" don't get is that within an application, there is only one Application class and only one instance of each of its helpers, at most (as per lazy loading as above). Sure, singletons are bad, but then again, only if they don't adhere to the real world. In my example, they do.
  • Gnuffo1
    Gnuffo1 over 13 years
    Or of course the one built into PHP - $_GLOBALS
  • dynamic
    dynamic about 13 years
    @Flavius: +1 is your solution basic the same to what sympfny does? symfony.com/doc/2.0/book/service_container.html The only problem I recognize is most IDE won't provice auto-complete feature. Anyway it seems you anticiped Sympfony by like 1 year
  • Einstein
    Einstein about 13 years
    @yes123: yes, Application is a container, and the classname can be injected.
  • dynamic
    dynamic about 13 years
    @Flavius: Dunno if you have noticed, But I have added the same solution using only one function in your answer :) check it out :)
  • Einstein
    Einstein about 13 years
    Yep, I've noticed it. I don't think I'd do it that way (it's a matter of taste) but it's a good addition. Thanks.
  • jjnguy
    jjnguy over 12 years
    While this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.