Understanding ZF2 Configuration

In Zend Framework 2 we no longer have the commanding application.ini, instead we got the option to configure our website or rather the modules on a per-module-basis. Furthermore, the modules are able to overwrite each others configuration. With this in mind, it makes it even more important to understand how ZF2 manages the configuration files of several modules internally. In this blog i will guide you guys through the internal process of the framework.

Where does configuration come from?

Before we go into the internals, let’s get a quick overview of where configuration usually comes from. Ultimately there’s only three places, that deliver configuration:

  1. ./config/application.config.php
  2. each Modules class Module
  3. ./config/autoload/(.*?).php

But wait, what about ./modules/(ModuleName)/config/module.config.php? Well, this file only exists for separation concerns. This config file will be called by the Module->getConfig(), so ultimately the config provider is the Module class itself. Knowing that let’s go through the configuration process.


The very first configuration file that will be loaded is the /config/application.config.php. When we take a quick look at the ZendSkeletonApplications index.php you’ll see that the application-config will be pulled into the Zend\Mvc\Application.

Taking a look into Application::init() you’ll notice that not much is happening. Basically the application.config.php will be set as an internal Service called ApplicationConfig and then the most interesting thing that happens is the following highlighted line. The Modules are going to be loaded. And this is where all the magic is happening, so let’s dive into that.


Now we get into the core of configuration, the ModuleManager. The ModuleManager itself actually does pretty much nothing, when it comes to configuration. What it does however is to trigger a couple of Events. The important Events triggered for us are:

Out of those, the most important one currently is ModuleEvent::EVENT_LOAD_MODULE. Now we need to find out what get’s triggered by this event. The targets of events are called “listeners”, so what’s more natural then to take a look at all the classes under Zend\ModuleManager\Listener\{name}Listener.php.

When it comes to the configuration of ZF2 the classes / listeners of relevance would be the Zend\ModuleManager\Listener\ConfigListener and Zend\ModuleManager\Listener\ServiceListener, let’s dive into them!

ConfigListener vs. ServiceListener

The big “duel” we’re interested in is the one about the ConfigListener vs. the ServiceListener. Let’s first go through the roles of each of them.

The ConfigListener

Ultimately what the ConfigListener does is to call the function getConfig() of the Module-Classes. This happens for every single Module. And all Module->getConfig() will be merged into one internal configuration.

The ServiceListener

The Role of the ServiceListener is similar. The ServiceListener ultimately calls all the other config functions of the Module classes. The exact functions that will be called are:

  • getServiceConfig() translates to $config['service_manager']
  • getControllerConfig() translates to $config['controllers']
  • getControllerPluginConfig() translates to $config['controller_plugins']
  • getViewHelperConfig() translates to $config['view_helpers']
  • getValidatorConfig() translates to $config['validators']
  • getFilterConfig() translates to $config['filters']
  • getFormElementConfig() translates to $config['form_elements']
  • getRouteConfig() translates to $config['route_manager']

The Load-Order

The very interesting question is now: Who’s last?

To make the long story short, the first function to be called is getConfig() and after that all functions provided by the several ServiceListener are called in the above listed order. So ultimately the specific functions like getServiceConfig() or getViewHelperConfig() will take priority over the configuration served by getConfig().

The /autoload/ configuration

The last things to load would be the configuration files served under config/autoload/{,*.}{global,local}.php. Those files could practically overwrite everything, again ;)

The load order here is alphabetically. The whole directory will be fetched and all matching PHP files will be merged into the existing configuration.


Internally a lot of stuff happens, when setting up the modules. And it is important to know about the load-order of the configuration steps. Finding out about this sure will leave me away from needless debugging time in the future. So whenever you encounter some problems with your configuration, now you know where to look for errors.

  1. application.config.php
  2. $module->getConfig()
  3. $module->get{,*}Config() (or ServiceListeners)
  4. /config/autoload/{,.*}{global,local}.php
22 Responses to Understanding ZF2 Configuration
  1. Deovrat Reply

    Great Explanation!
    Thank you so much!!

  2. Uk Reply

    hi man,

    Is there anyway that we can specify the default module ..my application.config.php looks like this

    'module_listener_options' => array(
    // Module class.
    'module_paths' => array(
    'config_glob_paths' => array(

    Is there anyway to load the Cool module by default ..not its loading the module Album (Or whatever module that is described last)

  3. Rob Durden Reply

    Sam, about the merging of the config files, wouldn’t that cause any sort of problems if one config file conflicts with the other one? And how exactly they are merged?

    Many thanks, Sam!
    Your articles are very helpful. Keep up the good work!

    • Sam Reply

      Hey Rob. What do you mean by “conflicts”? If there’s identical config keys, the values will simply be overwritten.

  4. wildrocket12 Reply

    Any new tutorials from yourself coming anytime soon? Have been looking forward to them. Also, did you do any video tutorials?

    • Sam Reply

      Hey there, truth be told: I’m fucking lazy…
      Though i have a bigger blog in the making right now, it will still take a week or two before i finish this one. This will be more of a experience story rather than a short tutorial. Still trying to figure out what i actually wanna showcase :S All i can say is: there WILL be more content, this blog ain’t dead – it’s just sleeping :)

      • wildrocket12

        Awesome, thanks for the quick reply. Am looking forward to the new posts. So what’s your new blog about?

      • Sam

        It will be about how i failed using the EventManager and how i overkilled the Separation of Concern :)

  5. Abhishek Reply

    ” And all Module->getConfig() will be merged into one internal configuration.”

    I am started to be working on a project that is already in progress. And i would like to get all the configuration at once.
    Is there any temporary file created where I can see all the module.config.php data at once.

    • Sam Reply

      This is explained in the article i think. You’ll always have access to the configuration via the ServiceLocator. $serviceLocator->get(‘config’);

      Alternatively you can always install ZendDeveloperToolbar for development and there you’ll see the merged config, too.

  6. Dominic Watson Reply

    With the ZF2 Skeleton application, they give you this by default:

    which results in something like:


    Which I think is wrong/bad… as the local is getting overridden by a global config.

    This is better, in my opinion:

    anything.local should ALWAYS be merged last. Local configuration should always override anything global.

    Resulting in:


    • Sam Reply

      in your example, aws.globa.php would be included before global.php. The directoy gets scanned in order by filename and is then matched against the regex-pattern for true/false.

      • tmquang6805

        Sorry Sam, but I disagree order load config with alphabetically filename. I think config files are loaded by user define.
        Example, I have 3 files config below (contains in config/autoload folder)
        – db.global.php
        – db.local.php
        – db.development.php
        And, in each file, return some thing like below

        I config global load config 3 times, and so on
        1 – ‘config/autoload/{,*.}{local,global,development}.php’,
        2 – ‘config/autoload/{,*.}{local,development,global}.php’,
        3 – ‘config/autoload/{,*.}{development,global,local}.php’,

        In controller – action, I dump data like below

        Result I got for 3 times like below
        1 – ‘/home/quangtm/workspace/private/zf2/config/autoload/db.development.php’
        2 – ‘/home/quangtm/workspace/private/zf2/config/autoload/db.global.php’
        3 – ‘/home/quangtm/workspace/private/zf2/config/autoload/db.local.php’

        Thanks you for your sharing

      • Sam

        Thank you for this share, that is indeed interesting. I was under the impression that the regular expression is just a match, but apparently I was wrong, gotta dig into the Mvc once more i guess, thanks for the hint!

      • Whitaker

        At the risk of necroing this, I think I figured out the alphabetically vs non issue.

        In tmquang’s example, the order is specifically delineated by the order of the stages (global, dev, local). For the example glob:


        the glob first tries the earliest option in the earliest brackets ( so the empty string before the comma in {,*.} ), and then all of the options from the second set of brackets. This attempts to load files:


        In that order.

        Then, it moves on to the second option from the first bracket ( the *. from {,*.}, and then tries all the values from the second brackets.

        This loads globs in this order:


        So, within those globs, files are being loaded alphabetically. That means that an imaginagy abc.global.php would be loaded before the aforementioned db.global.php.

        However, each of those globs is done independently (AFAICT).

        I had a problem where my glob looked like this:


        I wanted to allow something like


        to be loaded before


        However, the *. in the first brackets combined with the implied allowed empty strings in all the other brackets:


        Which produces this glob, which got loaded somewhere in the middle of my config loading.


        Within that glob, everything was being loaded alphabetically.

  7. Bineet chaubey Reply

    i have a module name Blog right now i am going to create a new configuration file for this module in Blog/config/autoload/abc.global.php and content of this file is
    return array(“mainearray” => array(‘facebookname’ => “abc, “facebookpassword” => “facebookpass” ));

    how we can access this info in main file
    $this->getController()->getServiceLocator()->get(‘config’); this above method does not work

    please help me

    • Sam Reply

      Hey, you would simply put this array in your module.config.php (there is no module/config/autoload !!) and then you’d have access to this configuration via:

      $this->getServiceLocator()->get('config')['mainearray'] (PHP 5.4 Syntax)

  8. Olive Reply

    Hi Sam!
    Great article again. I was looking for a complete list of the service listeners (especially for custom filters and validators).
    The ZF2 is so poor for advanced configuration…
    Thanks a lot!

  9. Ori Reply

    Could you confirm there’s no discrepancy between the last sentence at “The Load-Order” and steps 2 & 3 of “Conclusion”

    Thanks Sam

    • Sam Reply

      Looks identical to me :) And that’s what it should be like, what makes it difficult to understand? I may have to rewrite that part if it’s confusing…

      • Ori

        I’m sorry you are right. I equated priority for order.

        Could you cover the EventManager an example would be nice too.


      • Sam

        Are you asking for the order of all fired Events? That’s certainly an interesting topic, sadly nothing i’ll be able to cover in the near future. This is so much work :P

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">