6

I have recently read Miško Hevery's pdf guide to writing testable code in which its stated that you should limit your classes instanciations in your constructors. I understand that its what you should do because it allow you to easily mock you objects that are send as parameters to your class. But when it comes to writing actual code, i often end up with things like that (exemple is in PHP using Zend Framework but I think it's self explanatory) :

class Some_class
{
    private $_data;

    private $_options;

    private $_locale;

    public function __construct($data, $options = null)
    {
        $this->_data = $data;

        if ($options != null) {
            $this->_options = $options;
        }

        $this->_init();
    }

    private function _init()
    {
        if(isset($this->_options['locale'])) {
            $locale = $this->_options['locale'];

            if ($locale instanceof Zend_Locale) {
                $this->_locale = $locale;
            } elseif (Zend_Locale::isLocale($locale)) {
                $this->_locale = new Zend_Locale($locale);
            } else {
                $this->_locale = new Zend_Locale();
            }
        }
    }
}

Acording to my understanding of Miško Hevery's guide, i shouldn't instanciate the Zend_Local in my class but push it through the constructor (Which can be done through the options array in my example).

I am wondering what would be the best practice to get the most flexibility for unittesing this code and aswell, if I want to move away from Zend Framework.

Thanks in advance

2
  • Are you sure you want to move away from the Zend Framework? Unless you are actually planning to use something else the extra effort involved in abstracting away from it is useless. (Injecting the locale object properly, however, is a good idea) Mar 7, 2011 at 22:23
  • i don't plan to move away from Zend, at least not for this project, but i would rather make it Zend independant so I can reuse the code in an other project
    – JF Dion
    Mar 7, 2011 at 23:41

2 Answers 2

1

You are absolutely right, you should not hard-code a reference to Zend in the method.

You need a seam, a layer of abstraction, so that you can pass in Zend or any other framework. I don't know if PHP has a concept of interfaces, but those are a popular way to abstract implementations out of code.

I'd recommend Michael Feathers' book "Working Effectively with Legacy Code" for a detailed discussion of the topic.

1

This comes from a Java/C# bias; it may not make complete sense in PHP.

To make the code easier to test without removing the Zend framework:

If you can, inject a "Zend_Locale" directly. I personally find the optional array a bit ugly; it hides the dependencies of your class. I would have a none-optional locale parameter in the ctor. The DI Framework (or the creator of the object if you are doing it manually) is responsible for filling in the details.

If you can’t inject, and the logic needed to work out how to generate the "Zend_Locale" is not really the responsibility of "Some_class", I'd inject a factory. This will make unit testing a little easier (depending on the complexity of the logic) as you can easily give a stub.

If you want to move away from the Zend Framework then you need to look at any Zend framework items you use and generate a wrapper for them with interface for you too use in client code and anywhere you have a "new Zend_blah" then you need to either inject the instance or inject a factory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.