Having a PHP class have other classes as its properties

Hi,

Let’s say you have classes in a package.

Helpers\Cleaner
Helpers\Validator
Helpers\Time

And a function:

function test($foo, $bar, Helpers\\Cleaner $cleaner, Helpers\\Validator $validator, Helpers\\Time $time) {
    // Whatever
}

You create a class that holds all of them:

Helpers/Helper

Which would result in:

$helper->$cleaner
$helper->$validator
$helper->$time

So then you can have less parameters:

function test($foo, $bar, Helpers\\Help $helper) {
    // Whatever
}

Is there a name for this and is it considered good or bad practice?

Thanks.

Hi DrQuincy,

If your class ends up with a long list of dependencies, it could be a sign that it’s doing too much and needs to be refactored. Not knowing what the consuming class does, it’s difficult to say in this instance.

Another option might be to pass in a helper factory to the class, so it can retrieve instances of the helpers it needs. This is similar to your suggested approch, except that the contruction of the helper objects is kept in one location, and they’re only instantiated as needed.

or… you can use dependency injection with setters to inject the dependencies.

Though what you are referring to is called composition.

Isn’t that what the OP is already doing in his first example? Besides, that doesn’t actually help him reduce the amount of parameters, which is what he’s asking about.

Yeah… you are partially right about that although in the case of frameworks like Symfony2 you would only have a single method per dependency… not a constructor with a gigantic amount of args.

Thanks for the posts. I’ve been reading up a bit over the holidays and, related to this and the points you both made, wonder if you could help me be clear on what some of the terminology means.

  1. Am I right in saying a container class is a generic name for a class that holds other classes. So what I said that oddz confirmed as composition is actually a type of container class?
  2. Is a helper factory class as mentioned by fretburner one that creates objects based on input to the class? If so, am I right in saying you would not inject dependencies to a factory class?
  3. Does a dependency injection container get passed as a single object and then it creates objects on the fly? If so, I would guess they are similar to factories classes. In fact, what’s the difference?
  4. Inversion of control, what does this mean exactly?

Assuming I’ve understood correctly…I’m sure I’m wrong but don’t dependency injection containers and factory classes make for code that is harder to read and test? For example, take these two pieces of code.

Version 1:

function test(Foo $foo, Bar $bar, FooBar $fooBar) {
    $this->foo = $foo;
    $this->bar = $bar;
    $this->fooBar = $fooBar;
}

Version 2:

function test(DIContainer $dIContainer) {
    $this->foo = $dIContainer->getClass('foo');
    $this->bar = $dIContainer->getClass('bar');
    $this->fooBar = $dIContainer->getClass('fooBar');
}

While version 1 has more parameters, it’s far easier to understand. Version 2 doesn’t seem much better than creating the objects within test(). Or have I completely misunderstood?

Having thought about it, I’m wondering if I should leave my code as is and consider using Composition and/or reevaluating what classes do where parameters get too long. Are factories and DICs commonplace in PHP programming? Every time I get close to finishing my framework I learn something new and it makes me want to refactor. Currently my framework has no static classes or functions (though some classes have constant and static properties) and everything is injected properly. There are a handful of classes that have over five parameters in the constructor. Am I over analysing my code? I work on my own so my projects aren’t that big; my framework has about 50 classes for generic things like files, forms, sessions, eCommerce, database, data cleaning, data validation…

Thanks.

I’ll just start off by making it clear I’m not an expert in OOP… there are others here with more knowledge and experience, so the following is just my take and I’ll happily be corrected if I’m off the mark.

Composition is really just a name for the technique of having complex objects which are composed of simpler ones. This link might shed a little more light on containers.

Factories can have dependencies of their own - a data mapper factory might require a PDO instance, to pass in to the mappers it creates. At some point though, the line between factory and DIC begins to blur (see below).

To my mind, a DIC is like a super-factory… you can tell it how to create an instance of any type of class, and what dependencies that class has, and it can supply them (assuming it also knows how to create the dependencies). Imagine that you have a complicated object graph, you only need ask for an instance of class D. The DIC will instantiate A, pass it to the constructor of B, passes B into C and then C into D… handing you the object you wanted with all dependencies supplied.

It’s considered bad practice to pass a DIC into other objects and letting them get their dependencies, because then you’re introducing a dependency on the container and most of your classes just shouldn’t know about that - they should only be aware of the objects that they need to function.

You might want to check out this sample application - it’s written by the guy who wrote PHPUnit, as an example of how to build a testable app. I’ve found it very useful code to study.

That defeats the purpose of dependency injection. While in *some cases it might be appropriate to pass the entire container that is generally frowned upon. The idea is collect all services in a single location and inject only what is needed into other services (class instances). There are multiple ways this can be done. My best recommendation is to have a look at the Symfony 2 docs for the DI container component as it explains all the concepts much more thoroughly than anyone here ever could. When it comes down to it DI is really nothing more than a automated form of composition.

I’ve been a PHP professional for about six years now and one point I was just like you building my own frameworks and what not. However, I have learned with so much tried and true software out there it really is a loosing battle. I mean if you enjoy it and you aren’t really working on paying clients projects than fine. However, the second the project becomes paid by a client custom frameworks these days tend to do more harm than good unless you really have unique requirements or legacy code to deal with. However, for brand new projects it is more professional to use one of many open source projects out there. The increase in efficiency aside community support and completeness will always be unparalled to anything an individual or small team could create as a one off on *most clients budgets. Not to mention if some circumstance prevent the original team/individual from being able to work on a project the learning curve will be lower. Especially, if the client is able to be specific with technologies/open source projects used in job postings. Even long standing projects are all making use of other projects. Take Drupal 8 for instance. Did they build their own Router, DI container, template language, NO. They are making use of several pieces of the Symfony stack and that stack will probably only increase. So many of a new comers to the language who go off on tangents reinventing the wheel would be so much better served devoting themselves to an already established project. There is so much more to gain like networking opportunities and learning from some of the best in the industry. Not to mention learning to read others code in a large application context. Writing your own code is pretty easy but it really becomes a whole other ball game when you have to deal with something that has hit to many developers to count all with different skill levels. I’m not necessarily saying everyone should jump into Symfony but I am saying new comers and enthusiast in general would be better served becoming involved in established open source projects rather than attempting to reinvent wheels on their lonesome.

Thanks everyone.

I hear what you’re saying oddz but the kind of environment I work in it has (luckily!) been economically viable to build a simple framework and also is actually really useful in terms of how much quicker I can now build sites. I work alone so the projects tend to be quite small. I rarely lose clients but when I do they always have a different platform they use anyway and so the fact my code is bespoke is, by that point, irrelevant.