PHP Constructor Best Practices And The Prototype Pattern

March 9th, 2012 § 29 comments

If your knowledge of constructors ends with “the place where I put my object initialization code,” read on. While this is mostly what a constructor is, the way a developer crafts their class constructor greatly impacts the initial API of a particular class/object; which ultimately affects usability and extensibility. After all, the constructor is the first impression a particular class can make.

Constructors, in their current form, have been in PHP since 5.0.0. Previous to 5.0, PHP loosely followed the style similar to that of C++ where the name of the method matching the name of the class would act as the class constructor. PHP 5 brought us the __construct() “magic method” which greatly formalized the new object initialization routine.

Before jumping into some of the topics covered in this post, there are a few things you might want to be familiar with. First, be familiar with the SOLID principles, particularly the S (single responsibility principle), the L (Liskov substitution principle, commonly referred to as the LSP), and the D (dependency inversion principle). More to the point of the latter, review a previous post on Dependency Injection in PHP for background dependency injection specific to PHP.

The Constructor Signature

In PHP, you create a constructor by adding a method called __construct() to your class. The __construct() method is an instance method and as such, is not marked static. For all intents and purposes, consider the __construct() magic method as a special type of static object factory, one which will always return the type of the object requested via the new keyword.

In the above code, PHP will, upon executing new Foo(), internally create a new object from scratch, execute __construct() in the Foo class, and assign this object to the variable $object. Pretty standard stuff. What’s important to know here is that before new Foo(), the object did not exist. It is this fact alone that makes this completely different from any other kind of instance method. That said, without getting into the gritty details, it is this fact alone that excuses the __construct() method from the same rules of the LSP that might apply to other instance methods.

This means that all of the following are legal:

The above, with E_STRICT enabled, will not produce a warning. Yet, if you renamed all of the __construct methods to anything else, they will produce a E_STRICT warning like:

[code lang="bash"]
Strict standards: Declaration of Bar::somemethod() should be compatible with that of Foo::somemethod()
[/code]

Why is this the case? Simply put, the LSP referrers to sub-types of a particular object, and since before the __construct() method, no type exists (yet). This rules simply cannot apply to something that does not exist. For a more detailed response, go here.

What you should take away from this is that the best-practice is that each concrete object has a constructor with a signature that best represents how a consumer should fully instantiate that particular object. In some cases where inheritance is involved, “borrowing” the parents constructor is acceptable and useful. Furthermore, it is encouraged that when you subclass a particular type, that your new type should, when appropriate, have its own constructor that makes the most sense to the new subtype.

At this point, it should be noted that most other languages do not allow constructors to be marked final, be abstract, or be marked as statics (see above on the static note). Moreover, constructors should not appear in interfaces. In PHP, these rules do not apply, and are all possible. For the reasons listed above, a developer should avoid the practice of marking constructors final, making them abstract, and putting them interfaces, assuming they are trying to utilize PHP’s OO model in a SOLID way. In PHP 5.4, it is also worth knowing that by having constructors in interfaces breaks the common expectation that subtypes are capable of creating their own constructors in favor of enforcing a particular method signature.

Constructor Overloading

PHP does not have method overloading. This also applies to constructors. A class of a specific type can only have one constructor. Since this is the case, PHP developers sometimes loosen a methods signature in order to accommodate multiple use cases. This is done by removing or reducing the types enforced in the constructors signature to allow for more varied types to be passed in by the consumer.

This is an acceptable best practice when done appropriately. What does appropriately mean? What is “appropriate” is, of course, very much subjective. Generally speaking, the differences in the various signatures supported should be minimal at best, yet meaning should still communicated through the name of the parameters. For example, let’s take this constructor:

The above signature __construct($driver) technically supports 3 effective signatures:

The actual signature has not changed, but it is represented all 3 effective signatures that can be further described by the PHP DocBlock.

Constructor Injection

At this point in the PHP community and in PHP-centric developer circles, it is generally accepted that injecting your dependencies is a best-practice. How developers go about injecting these dependencies is still very much debated and, in-part, up to personal and/or team preference.

There are several such methods of dependency injection: interface injection, setter injection and constructor injection to name the primary forms. For the purposes of this post, constructor injection is our primary candidate for discussion.

In short, constructor injection is a pattern of injecting all of your required dependencies into a constructor. These dependencies are usually other objects, often called services. The primary benefit of constructor injection is that after you instantiate the target object, generally, it is in the complete “ready state,” meaning that it is ready to do real work. A typical constructor signature sporting constructor injection looks like this:

The above example clearly demonstrates that before a developer can use a UserRepository object, they must first inject it with a UserMapper object.

In PHP, while in recent times we’ve started favoring dependency injection (which can add some complexity to code), we have traditionally gravitated towards code that is easy write and easy to use. Practicing good dependency injection can be tedious at times and, in many cases, dependencies for objects can be stubbed by a sensible default. This practice is also known by the name of Poka-Yoke. It allows us to develop an API that supports explicit injection of dependencies while promoting ease of use in common or majority use cases. Consider the following code:

While the UserRepository allows you to inject your dependency of the UserMapper, it will, if one was not provided, instantiate a sensible default UserMapper for you. The benefits are that in the most common use cases, it is a one step usage scenario (just instantiate the UserRepository). But in unit testing scenarios or scenarios where you want to inject an alternate implementation of a UserMapper, that can be achieved through the constructor.

Dynamic Class Instantiation

Generally speaking, the following code, while legal, should be used very seldom, and only when other possible instantiation patterns have been exhausted:

Why is this a bad pattern? First, it makes the assumption up front that the constructor signature is free from any required parameters. While this is good for object types that are already known to this factory, it might not always be true of a consumers subtype of the base object in question. This patten should never be used on objects that have dependencies, or in situations where it is conceivable that a subtype might have dependencies because this takes away the possibility for a subtype to practice constructor injection.

Another problem is that instead of managing an object, or a list of objects, you are now managing a class name, or list of class names in addition to an object or list of objects. Instead, one could simply manage the objects.

If, on the other hand, you know this particular object type is no more than a value object (or similar), with no chance of it needing dependencies in subtypes, you can then cautiously use this instantiation pattern.

Prototype Pattern

So how does one create an unlimited number of objects of a particular type, with dependencies in tact, each with slight variations? Enter the prototype pattern. This is an important pattern to keep handy when you know that you’ll have objects that need to be replicated in some way and they also have service dependencies that need to be injected.

To draw a parallel, this is similar to how Javascript handles its object model. To sum prototyping up in Javascript: functions and properties are defined once per prototype rather than once per object. The new keyword instructs the engine/runtime to create a copy of the prototype and assign to a variable for further specification and interaction.

This is similar to what the Prototype Pattern does in an object-oriented inheritance model. Up front, you create a prototypical instance. This instance will have all its dependencies injected, and any shared configuration and/or values setup. Then, instead of calling new again, a factory (or the consumer) will call clone on the object (a shallow clone will be made), and a new object will be created from the original prototypical object. This newly cloned object can then be further specified, injected with the variations that make this new object unique, thus interacted with as a unique object.

Lets consider the following example involving a database connection and the Row Gateway pattern. We want to iterate a dataset from a database and during iteration, present each row as a RowGateway object. One way of handling this would be to get the array of data from the database, then during iteration, create a new RowObject from scratch injecting the database connection:

A UserRepository will be constructed with a database adapter object. It will then query the database, returning an array of all the rows that satisfied that query. With each row of data, it will create a fresh RowObject from scratch, injecting all the dependencies, configuration and the row data.

At first glance, you might ask “what if I have a specialized version of RowGateway I want to use?” That solution can be easily handled by instead of hard-coding the RowGateway class, but by use the Dynamic Class Instantiation pattern described above:

This partially solves the problem in that now we can now use our own specialized class for the RowGateway implementation, but this too has its own special set of limitations. First, we are incorrectly making the assumption that the constructor signature of a subtype of RowGateway is exactly the same as the base type. This means that if a subtype has additional dependencies, that class will need to do the static dance in order to locate and consume those dependencies that it needs to achieve its specialized functionality. By making this assumption of the classes constructor signature, we’re limiting the consumers ability to practice polymorphism in the subtypes that they might need to have created.

For example, if a consumer wanted to be able to have a RowGateway object that wrote data to one specific database, but refreshed its data from a different database, how might one be able to inject two different DbAdapters into a RowGateway object to achieve this end result?

The answer is to use the Prototype Pattern, and in practice (via pseudo-code), looks like this:

By using a prototypical instance as the base for all future instances, we now allow the consumer the ability to extend this base implementation using sound object-oriented/polymorphic best-practices to achieve their end result. So, assuming our above example of the read/write adapter, a consumer can write:

Parting Words

Be nice to people who want to consume and extend your code. A constructor is more than just a place for initialization code. How you craft your constructors, the patterns you use for their signatures, and how you expect to get new instances of objects greatly affects the ability of consumers to extend your code without having to jump through too many hoops in order form them to achieve their specialized use case. It is always better to fall back on SOLID object-oriented practices than to limit someones possibilities by forcing them into coding patterns that require reading in-depth documentation on how the original author expects someone to extend their code.

Tagged , , , ,

  • http://gregk.me Greg K

    Good post. I never knew the pattern for a sensible default for a dependency was called Poka-Yoke :)

  • Pingback: PHP Constructor Best Practices And The Prototype Pattern | DBGLORY 4 YOU

  • http://codeaid.net Andris

    Excellent article as always. I’d be interested to learn more about background dependency injection. Sounds interesting. And please more of these advanced articles!

  • Daniel

    “…static object factory…” = class constructor

    Maybe a bit OOP purist but I’ve never thought of a
    class constructor this way? I think your making it sound
    more complicated?

    Enjoyed reading.

  • Mahbubur Rahman

    Nice & Cool Article.

  • http://geekpub.de Arne

    Nice stuff, but it would be cool if you could post a more “simple” example ;)

  • http://blog.wsoczynski.pl Wojciech Soczyński

    I would not call the “__construct” method a static object factory. In PHP all magic methods are the implementation of the template method pattern. They are basically “hooks” for altering the engine’s default behavior. So the __construct method it is an initializer – not a constructor. It does not return the new instance, the instance is created before the __constructor method is called and it’s role is to prepare the object for usage.

    • Dan

      Yes. I agree with you Wojciech. That’s what the PHP manual says about constructors: initializers called AFTER the object was created in memory, and the assignment of the instance to the variable is done by the ‘new’ keyword. Nice article anyway. The ‘clone’ operator has finally a role in modern programming :).

  • Ren

    I’m going to have to disagree. The prototype pattern is evil.

    Anything that forces extra methods on objects (initialize) isn’t good. Particularly when the constructor is meant to initialize an object. It’s like ORMs forcing model objects to have a load of properties and methods. It’s just bad.

    Passing in a RowGateway factory (even as a closure) seems a far better alternative.

  • http://ralphschindler.com/ Ralph Schindler

    @daniel + @Wojciech, I am calling the __construct a “static object factory” to impress that it is not the same as any instance method, and therefore, a developers general understanding of how the LSP affects instance method signatures does not apply to constructors. Too many times I’ve seen developers stick with a parent classes constructor signature because they thought it was wrong (in terms of the LSP) to change its signature in a subtype. In fact, I advocate the opposite: each subtype should have its own constructor that makes the most sense when creating new instances of that particular type.

    I call it out as static to impress the fact that in most class based languages, constructors are not allowed to be or belong inside interfaces… just like static methods. Interfaces are there to expose and enforce the behaviors of a subtype/object after its been instantiated. The fact that you have an object only after __construct instantiation is simply a side effect of new and __construct and not a behavior of the object itself.

    @Ren When you swapped out the RowGateway for Closure, you shifted any error checking on the type from the constructor to a runtime check after the closure was called to ensure it produced the expected result. The closure could do anything at that point, and having it in the UserRepository signature doesn’t clearly communicate the relationship between UserRepository and RowGateway. You’re example works, and is suitable if you want more of a documentation driven approach to coding as opposed to a type and interface approach to creating new objects when iterating row data. I say “documentation driven” b/c by looking at a signature that include callable, the next question is “hmm, a closure can do and produce anything, i wonder what the function will get passed, where do I start?”

    Also, keep in mind, I used initialize because it is a common name you’ll see in the Prototype Pattern, it could very well be anything, it could be setData() something you’ll see anyway inside a RowGateway object. So in that case, no extra methods would have been required for the target of the cloning.

    -ralph

  • Gerard

    Constructor injection: “The primary benefit of constructor injection is that after you instantiate the target object, generally, it is in the complete “ready state,” meaning that it is ready to do real work”

    I get so very annoyed at this practice, especially in frameworks, and even more so where there is a 1:1 class:file relationship, because file access is expensive, and why load something if it’s not going to be used? It screams acedemia.

    Yes, only inject a “ready state” for things that *will* be used, lazy load things that *might* be used, and *only* load them when required. Right?

    I must be getting very disallusioned by frameworks and the influence they’re having on php, because I seem to be getting more and more so very annoyed at things like this. Then again, maybe I just need to get laid.

    On the bright side, there’s some useful information to had from the article.

  • http://blog.wallbash.com Edorian

    Very nice article Ralph, thanks!

    I like the “static object factory” analogy a lot and use it myself to describe why I think it is ok to have static methods on a class that return a instance of that class. (Constructor overloading without having everything in __construct). A new is a “static”/”evil”/”global state” call anyways so replacing it by “DateTime::createFromFormat” is fine :)

    To the prototype idea:

    First of thanks for “porting” that over to php with some sample code. It makes for a good linkable example :)
    Second: Using replacing the $rowGatewayPrototype with a $rowGatewayFactory or (to allow the outside to make the decission) a rowGatewayProducer) would be the more “classic” approach in PHP to do that? Did i get that right?

  • Giorgio Sironi

    I am pleased with constructor injection becoming a staple for PHP code. However when multiple construction signatures should be supported, I prefer to define static Factory Methods each with his own strict signature, that return a new instance of ‘self’. These methods support descriptive names like ‘fromX’ and ‘fromY’, and eliminate the conditionals.

  • Ren

    @Ralph The closure was just an implementation detail of the factory method pattern. Defining an interface and an implementation would eliminate the documentation problem.

    However the Prototype Pattern enforces, what I’d consider, some bad practices.

    - Objects not fully initialized after the constructor finishes.
    - Relying on magic methods ( __clone() ).

  • http://lebenplusplus.de/ Gabriel

    @Gerard: I think the issue of file access being expensive is somewhat mitigated when you’re using a Bytecode cache like APC (which you should do anyway).

  • http://blog.wsoczynski.pl Wojciech Soczyński

    @Giorgio – I agree with you, but in my opinion we don’t need multiple constructor signatures, as you said we can have static factory methods witch convert their arguments to fit the constructor. I think also, that in case when your object doesn’t need some fields initialized (in some usage contexts), you should create a separate class with a different constructor, rather than have constructors with different signatures.

  • http://pooteeweet.org Lukas

    @Gerard i assume you are partially complaining about PSR-0 here? the right solution is for APC to finally become hosted friendly and be bundled with PHP. but there are other solutions for shared host users without APC, including simply having a script that appends common classes into a single file that is loaded once.

    as for your concern about lazy loading. most of the time if you need to lazy load a dependency, then probably you should move the logic to a different class anyway. classes with lots of optional dependencies are a code smell. additionally you can always still implement lazy creating of connections etc. once you are just creating objects without doing expensive stuff like opening files or remote connections, then you solved most of the issues from making instances of optional dependencies.

  • http://akrabat.com/ Rob…

    Whilst I appreciate the benefits that the prototype pattern brings, like Ren, I’m not completely comfortable with objects that aren’t fully initialised after the constructor finishes. When I was cutting my teeth on C++ back in the days of Win16, this was called two-stage construction and was not considered a wise design decision. Maybe I’m just old fashioned and old habits die hard.

    Regards,

    Rob…

  • Greg

    Ralph, very nice post. I’m always a little more a little more educated and in awe of your references.

    This would be ideal for the Zend Paginator?

    Maybe Off Topic, but is the Zend_Autoloader SOLID?

  • http://www.johncongdon.com John Congdon

    I think Ralph is just sharing options. I appreciate seeing code in a new way. I like putting pieces of information like this into my toolbox, as it helps me think about all potential solutions and not just fall back to what I already know and use.

    At the same time, having all of these useful comments has been great to also give me an insight into other opinions.

    Thank you for the time to write this post and share.

  • http://dteruel.net.br Mingomax

    Ralph, hi from Brazil, your post its very nice and clarified certain dogmas that had on the use of some patterns and your article told me.

    Excellent.

    Tks.

  • http://objectic.cc/ Niko Kivelä

    Against what @Ren said, I don’t think that __clone method should be considered “magic method” (even tho it is) in a way as __call or __set magic methods but in a way as __construct or __destruct. There’s a solid unambiguous point when objects __clone method is called, on keyword clone (compare to new keyword).

    One point to notice, even tho you cannot overload clone method, you can “borrow” it from objects parent in a way you can call superclass’ constructor calling parent::__construct

  • http://sitegrind.nl Jeroen Franse

    Very nice article. It gives a solution (one of many as I understand from comments) to a problem I’ve been struggling with for a long time. It gives practical solutions for implementing Dependency Injection.

    The code for the Prototype Pattern line 30, I believe the assignment (or reference) is not made correctly. Shouldn’t that be:

    $this->rowGatewayPrototype = ($rowGatewayPrototype) ? $rowGatewayPrototype : new RowGateway($this->dbAdapter, ‘user’)

    instead?

  • Alex

    Even though overloading is not permitted, you can post a variable number of arguments. This allows you to handle the function/constructor/special functions essentially the same as with overloading, save the code must be wrapped/integrated together. Nice work around if you need it.

  • http://www.farfromfearless.com Chris Murphy

    Great article, I learned more in the last 10 minutes from reading this compared to scouring StackOverflow; it was nice to read something intelligent about constructor patterns with great examples, vs the typical “…don’t ever do this… just don’t… ever.”

  • Michael Davidson

    I can see how this example makes sense whenever you are using classes that already exist; however, it would seem more prudent to use an interface for new APIs. Then again, maybe that’s the point.

  • http://www.greenesweb.com Amit Sharma

    Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error.

  • Pingback: Some ZF2 stuff « Andrei Boar

  • Pingback: Database and models | Lma Group

What's this?

You are currently reading PHP Constructor Best Practices And The Prototype Pattern at Ralph Schindler.

meta