zend-config For All Your Configuration Needs

Different applications and frameworks have different opinions about how
configuration should be created. Some prefer XML, others YAML, some like JSON,
others like INI, and some even stick to the JavaProperties format; in Zend
Framework, we tend to prefer PHP arrays, as each of the other formats
essentially get compiled to PHP arrays eventually anyways.

At heart, though, we like to support developer needs, whatever they may be, and,
as such, our zend-config component
provides ways of working with a variety of configuration formats.


zend-config is installable via Composer:

$ composer require zendframework/zend-config

The component has two dependencies:

  • zend-stdlib, which provides some
    capabilities around configuration merging.
  • psr/container, to allow reader and
    writer plugin support for the configuration factory.

Latest version

This article covers the most recently released version of zend-config, 3.1.0,
which contains a number of features such as PSR-11 support that were not
previously available. If you are using Zend Framework, you should be able to
safely provide the constraint ^2.6 || ^3.1, as the primary APIs remain the

Retrieving configuration

Once you’ve installed zend-config, you can start using it to retrieve and access
configuration files. The simplest way is to use ZendConfigFactory, which
provides tools for loading configuration from a variety of formats, as well as
capabilities for merging.

If you’re just pulling in a single file, use Factory::fromFile():

use ZendConfigFactory;

$config = Factory::fromFile($path);

Far more interesting is to use multiple files, which you can do via
Factory::fromFiles(). When you do, they are merged into a single
configuration, in the order in which they are provided to the factory. This is
particularly interesting using glob():

use ZendConfigFactory;

$config = Factory::fromFiles(glob('config/autoload/*.*'));

What’s particularly interesting about this is that it supports a variety of

  • PHP files returning arrays (.php extension)
  • INI files (.ini extension)
  • JSON files (.json extension)
  • XML files (using PHP’s XMLReader; .xml extension)
  • YAML files (using ext/yaml, installable via PECL; .yaml extension)
  • JavaProperties files (.javaproperties extension)

This means that you can choose the configuration format you prefer, or
mix-and-match multiple formats, if you need to combine configuration from
multiple libraries!

Configuration objects

By default, ZendConfigFactory will return PHP arrays for the merged
configuration. Some dependency injection containers do not support arrays as
services, however; moreover, you may want to pass some sort of structured object
instead of a plain array when injecting dependencies.

As such, you can pass a second, optional argument to each of fromFile() and
fromFiles(), a boolean flag. When true, it will return a
ZendConfigConfig instance, which implements Countable, Iterator, and
ArrayAccess, allowing it to look and act like an array.

What is the benefit?

First, it provides property overloading to each configuration key:

$debug = $config->debug ?: false;

Second, it offers a convenience method, get(), which allows you to specify a
default value to return if the value is not found:

$debug = $config->get('debug', false); // Return false if not found

This is largely obviated by the ?: ternary shortcut in modern PHP versions,
but very useful when mocking in your tests.

Third, nested sets are also returned as Config instances, which gives you the
ability to use the above get() method on a nested item:

if (isset($config->expressive)) {
    $config = $config->get('expressive'); // same API!

Fourth, you can mark the Config instance as immutable! By default, it acts
just like array configuration, which is, of course, mutable. However, this can
be problematic when you use configuration as a service, because, unlike an
array, a Config instance is passed by reference, and changes to values would
then propagate to any other services that depend on the configuration.

Ideally, you wouldn’t be changing any values in the instance, but
ZendConfigConfig can enforce that for you:

$config->setReadOnly(); // Now immutable!

Further, calling this will mark nested Config instances as read-only as well,
ensuring data integrity for the entire configuration tree.

Read-only by default!

One thing to note: by default, Config instances are read-only! The
constructor accepts an optional, second argument, a flag indicating whether or
not the instance allows modifications, and the value is false by default.
Whenever you use the Factory to create a Config instance, it never enables
that flag, meaning that if you return a Config instance, it will be read-only.

If you want a mutable instance from a Factory, use the following construct:

use ZendConfigConfig;
use ZendConfigFactory;

$config = new Config(Factory::fromFiles($files), true);

Including other configuration

Most of the configuration reader plugins also support "includes": directives
within a configuration file that will include configuration from another file.
(JavaProperties is the only configuration format we support that does not have
this functionality included.)

For instance:

  • INI files can use the key @include to include another file relative to the
    current one; values are merged at the same level:

    webhost = 'www.example.com'
    @include = 'database.ini'
  • For XML files, you can use XInclude:

    <?xml version="1.0" encoding="utf-8">
    <config xmlns:xi="http://www.w3.org/2001/XInclude">
      <xi:include href="database.xml"/>
  • JSON files can use an @include key:

      "webhost": "www.example.com",
      "@include": "database.json"
  • YAML also uses the @include notation:

    webhost: www.example.com
    @include: database.yaml

Choose your own YAML

Out-of-the-box we support the YAML PECL extension
for our YAML support. However, we have made it possible to use alternate
parsers, such as Spyc or the Symfony YAML component, by passing a callback to the
reader’s constructor:

use SymfonyComponentYamlYaml as SymfonyYaml;
use ZendConfigReaderYaml as YamlConfig;

$reader = new YamlConfig([SymfonfyYaml::class, 'parse']);
$config = $reader->fromFile('config.yaml');

Of course, if you’re going to do that, you could just use the original library,
right? But what if you want to mix YAML and other configuration with the
Factory class?

There aer two ways to register new plugins. One is to create an instance and
register it with the factory:

use SymfonyComponentYamlYaml as SymfonyYaml;
use ZendConfigFactory;
use ZendConfigReaderYaml as YamlConfig;

Factory::registerReader('yaml', new YamlConfig([SymfonyYaml::class, 'parse']));

Alternately, you can provide an alternate reader plugin manager. You can do that
by extending ZendConfigStandaloneReaderPluginManager, which is a barebones
PSR-11 container for use as a plugin manager:

namespace Acme;

use SymfonyComponentYamlYaml as SymfonyYaml;
use ZendConfigReaderYaml as YamlConfig;
use ZendConfigStandaloneReaderPluginManager;

class ReaderPluginManager extends StandaloneReaderPluginManager
     * @inheritDoc
    public function has($plugin)
        if (YamlConfig::class === $plugin
            || 'yaml' === strtolower($plugin)
        ) {
            return true;

        return parent::has($plugin);

     * @inheritDoc
    public function get($plugin)
        if (YamlConfig::class !== $plugin
            && 'yaml' !== strtolower($plugin)
        ) {
            return parent::get($plugin);

        return new YamlConfig([SymfonyYaml::class, 'parse']);

Then register this with the Factory:

use AcmeReaderPluginManager;
use ZendConfigFactory;

Factory::setReaderPluginManager(new ReaderPluginManager());

Processing configuration

zend-config also allows you to process a ZendConfigConfig instance and/or
an individual value. Processors perform operations such as:

  • substituting constant values within strings
  • filtering configuration data
  • replacing tokens within configuration
  • translating configuration values

Why would you want to do any of these operations?

Consider this: deserialization of formats other than PHP cannot take into
account PHP constant values or class names!

While this may work in PHP:

return [
    AcmeComponent::CONFIG_KEY => [
        'host' => AcmeComponent::CONFIG_HOST,
        'dependencies' => [
            'factories' => [
                AcmeMiddlewareAuthorization::class => AcmeMiddlewareAuthorizationFactory::class,

The following JSON configuration would not:

    "AcmeComponent::CONFIG_KEY": {
        "host": "AcmeComponent::CONFIG_HOST"
        "dependencies": {
            "factories": {
                "AcmeMiddlewareAuthorization::class": "AcmeMiddlewareAuthorizationFactory::class"

Enter the Constant processor!

This processor looks for strings that match constant names, and replaces them
with their values. Processors generally only work on the configuration values,
but the Constant processor allows you to opt-in to processing the keys as

Since processing modifies the Config instance, you will need to manually
create an instance, and then process it. Let’s look at that:

use AcmeComponent;
use ZendConfigConfig;
use ZendConfigFactory;
use ZendConfigProcessor;

$config = new Config(Factory::fromFile('config.json'), true);
$processor = new ProcessorConstant();

// ['AcmeMiddlewareAuthorization' => 'AcmeMiddlewareAuthorizationFactory']

This is a really powerful feature, as it allows you to add more verifications
and validations to your configuration files, regardless of the format you use.

In version 3.1.0 forward

The ability to work with class constants and process keys was added only
recently in the 3.1.0 version of zend-config.

Config all the things!

This post covers the parsing features of zend-config, but does not even touch on
another major capability: the ability to write configuration! We’ll leave that
to another post.

In terms of configuration parsing, zend-config is simple, yet powerful. The
ability to process a number of common configuration formats, utilize
configuration includes, and process keys and values means you can highly
customize your configuration process to suit your needs or integrate different
configuration sources.

Get more information from the zend-config

Source: Zend feed

Laracon Online – Last Day For Early Bird Tickets

Today is the last chance for you to join over 3,000 developers and get an early bird ticket to Laracon Online for just $10. Each ticket purchase includes access to the live event video, conference swag, and a special Slack channel for hanging out and mingling during the event. With your ticket, you can sit on your couch and watch it all live!

Laracon Online will be held on March 8th, 2017 with opening remarks at 8:45 AM EST. If you can’t attend that day, all the talks will be recorded and available online for viewing at your convenience shortly after the conference ends.

Conference Swag

To bring you the true conference experience we are proud to be partnering with some of the biggest companies in the industry to offer you some awesome digital swag. Here is everything that is already confirmed:


Linode is offering a $20 discount to everyone on their cloud hosting.


Nexmo is offering 10EUR or $10.55 off their cloud-based communication APIs. Everything from SMS messaging, to voice, to authentication.


Deploy Bugsnag to your production application and get a free, limited edition, ultrasoft Bugsnag t-shirt.


Get a free .co domain registration with email and whois privacy for one year. A $20 value!


Blackfire is offering 30% off their Profiler and Premium editions. This is for first year of annual subscriptions and valid through March 31st.


If you make a purchase of Postmark credits within three months of Laracon Online, they’ll double your credits. It doesn’t matter how many credits you purchase. Buy $10,000 in credits, get $10,000 in credits free!

With early bird tickets at only $10, it’s an awesome deal and the digital goodies more than pay for the price of admission. Get your ticket today before the price goes up to $20 tomorrow.

Source: Laravel News

Laravel 5.5 Will Be The Next LTS Release

Version 5.1 was Laravel’s first LTS release and its two-year window of bug fixes are coming to an end this year. There have been a few people questioning if another LTS would be released and version 5.5 would be the next in line if it did happen.

Just today Laravel announced on Twitter that Laravel 5.5 will, in fact, continue the LTS line:

Just as the previous LTS this will include two years of bug fixes and three years of security updates.

For those not familiar with long-term support, these are special versions that are feature locked at the date of release. They do not get any new features but keep getting bug fixes and security updates throughout the maintenance window.

Source: Laravel News

How to Reduce Conditionals in Your Views

In the previous episode, we constructed multiple conditionals to determine which set of HTML should be displayed. For our basic example, the outcome was simple enough. However, for real-life projects, you may find that this quickly bloats your views and makes them difficult to reason about. Instead, let me show you a useful technique that involves applying polymorphism to dynamically load the proper view partial.
Source: Laracasts

Clarity and Rendering Subscription-Only Content

In this video, we’ll take a few moments to discuss clarity, double-negatives, and the potential they have to introduce bugs. Then, we’ll setup a template for rendering subscription-only content, while providing the necessary call-to-action for guests and deactivated users.
Source: Laracasts

PHP and SQL Server for Linux

This week we tested the public preview of Microsoft SQL Server for Linux
using PHP 7 with our component zendframework/zend-db.

Microsoft announced the availability of a public
preview of SQL Server for Linux on the 16th of November, 2016. This new
version of SQL Server has some interesting features such as:

  • transparent data encryption;
  • always encrypted;
  • row level security;
  • in-memory tables;
  • columnstore indexing;
  • native JSON support;
  • support for in-database analytics with R-integration.

Moreover, the performance of the new DBMS seems to be very impressive. Microsoft
published a case study with 1.2 million requests per second with In-Memory OLTP
on a single commodity server

We tested the last preview of SQL Server (CTP1.2 – using a Vagrant
box with Ubuntu 16.04 and 4 GB RAM.

Install SQL Server on Linux

We followed the instructions list on the Microsoft website
to install SQL Server for PHP on Ubuntu 16.04.

To ensure optimal performance of SQL Server, the Ubuntu box should have at least
4 GB of memory.

The first step is to add the GPG key for the Microsoft repositories.

$ sudo su
$ curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
$ curl https://packages.microsoft.com/config/ubuntu/16.04/mssql-server.list > /etc/apt/sources.list.d/mssql-server.list
$ exit

Then we can update the repository list and install the mssql-server package,
using the following commands:

$ sudo apt-get update
$ sudo apt-get install mssql-server

Now we can run the setup for sqlserver. We will be required to accept the EULA and
choose a password for the System Administrator (SA).

sudo /opt/mssql/bin/sqlservr-setup

After the installation, we will have SQL Server running on Linux!

Install the command line utility for SQL Server

Now that we have the DBMS running, we need a tool to access it. Microsoft
provides a command line tool named sqlcmd. This program is very similar to the
MySQL client tool, quite familiar to PHP developers.

To install sqlcmd, we need to run the following commands:

$ sudo su
$ curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-tools.list
$ exit
$ sudo apt-get update
$ sudo apt-get install msodbcsql mssql-tools unixodbc-dev
$ echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
$ echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
$ source ~/.bashrc


Though the Microsoft documentation does not indicate it, we also installed
msodbcsql; without it, we ran into dependency issues.

If the installation was successful, we can start using the command line tool.
For instance, we can ask for the SQL Server vesion using the following

$ sqlcmd -S localhost -U sa -P yourpassword -Q "SELECT @@VERSION"

where yourpassword should be replaced with the SA password that you choose
during the SQL Server setup.

This command will return output like the following:

Microsoft SQL Server vNext (CTP1.2) - (X64)
	Jan 10 2017 19:15:28
	Copyright (C) 2016 Microsoft Corporation. All rights reserved.
	on Linux (Ubuntu 16.04.1 LTS)

Install the SQL Server extension for PHP

Next, we need to install the PHP extension for SQL Server. This can be done
using PECL.


If you do not have PECL installed on Ubuntu, you can install it with the
following command:

$ sudo apt-get install php-dev

To install the sqlsrv and pdo_sqlsrv extensions for PHP, we need to execute
the following commands:

$ sudo apt-get install unixodbc-dev gcc g++ build-essential
$ sudo pecl install sqlsrv pdo_sqlsrv

Finally, we need to add the directives extension=pdo_sqlsrv.so and
extension=sqlsrv.so to our PHP configuration (generally php.ini). In our
case, running Ubuntu (or any other Debian-flavored distribution) we have the
PHP configuration files stored in /etc/php/7.0/mods-available. We can create
sqlsrv.ini and pdo_sqlsrv.ini containing the respective configurations. As
a last step, we need to link these configurations to our specific PHP environments.
For this, you can have two choices:

  • For Ubuntu, you can use the phpenmod command.
  • Alternately, you can symlink to the appropriate directory.

For our purposes, we are using PHP 7.0, from the CLI SAPI, so we can do either of the following:

# Using phpenmod:
$ sudo phpenmod -v 7.0 -s cli sqlsrv pdo_sqlsrv
# Manually symlinking:
$ sudo ln -s /etc/php/7.0/mods-available/sqlsrv.ini /etc/php/7.0/cli/conf.d/20-sqlsrv.ini
$ sudo ln -s /etc/php/7.0/mods-available/pdo_sqlsrv.ini /etc/php/7.0/cli/conf.d/20-pdo_sqlsrv.ini

Integration tests with zend-db

We used the above information to add support for SQL Server to the
zendframework/zend-db vagrant
configuration, used by developers to test against the various database platforms
we support.

We updated the Vagrantfile,
enabling integration tests for MySQL, PostgreSQL and SQL Server on Linux, to
read as follows:

$install_software = <<SCRIPT
export DEBIAN_FRONTEND=noninteractive
apt-get -yq update

apt-get -yq install postgresql

# Allow external connections to PostgreSQL as postgres
sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" /etc/postgresql/9.5/main/postgresql.conf
sed -i "s/peer/trust/" /etc/postgresql/9.5/main/pg_hba.conf
echo 'host all all trust' >> /etc/postgresql/9.5/main/pg_hba.conf
service postgresql restart

debconf-set-selections <<< "mysql-server mysql-server/root_password password Password123"
debconf-set-selections <<< "mysql-server mysql-server/root_password_again password Password123"
apt-get -yq install mysql-server

# Allow external connections to MySQL as root (with password Password123)
sed -i 's/' /etc/mysql/mysql.conf.d/mysqld.cnf
mysql -u root -pPassword123 -e 'USE mysql; UPDATE `user` SET `Host`="%" WHERE `User`="root" AND `Host`="localhost"; DELETE FROM `user` WHERE `Host` != "%" AND `User`="root"; FLUSH PRIVILEGES;'
service mysql restart

# More info here: https://www.microsoft.com/en-us/sql-server/developer-get-started/php-ubuntu

curl -s https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl -s https://packages.microsoft.com/config/ubuntu/16.04/mssql-server.list > /etc/apt/sources.list.d/mssql-server.list
apt-get -yq update
apt-get -yq install mssql-server
printf "YESnPassword123nPassword123nyny" | /opt/mssql/bin/sqlservr-setup

curl -s https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-tools.list
apt-get -yq update
ACCEPT_EULA=Y apt-get -yq install msodbcsql mssql-tools unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> /home/vagrant/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> /home/vagrant/.bashrc
source /home/vagrant/.bashrc

$setup_vagrant_user_environment = <<SCRIPT
if ! grep "cd /vagrant" /home/vagrant/.profile > /dev/null; then
  echo "cd /vagrant" >> /home/vagrant/.profile

Vagrant.configure(2) do |config|
  config.vm.box = 'bento/ubuntu-16.04'
  config.vm.provider "virtualbox" do |v|
    v.memory = 4096
    v.cpus = 2

  config.vm.network "private_network", ip: ""

  config.vm.provision 'shell', inline: $install_software
  config.vm.provision 'shell', privileged: false, inline: '/vagrant/.ci/mysql_fixtures.sh'
  config.vm.provision 'shell', privileged: false, inline: '/vagrant/.ci/pgsql_fixtures.sh'
  config.vm.provision 'shell', privileged: false, inline: '/vagrant/.ci/sqlsrv_fixtures.sh'
  config.vm.provision 'shell', inline: $setup_vagrant_user_environment

This vagrant configuration installs Ubuntu 16.04 with 4 GB of RAM and the
following databases (user and password are reported in parenthesis):

  • MySQL 5.7.17 (root/Password123)
  • PostgreSQL 9.5 (postgres/postgres)
  • SQL Server (sa/Password123)

We can use this virtual machine to run PHPUnit for the
zend-db integration tests. If you want to test this vagrant box, you can clone
the zend-db repository and run the following command:

$ vagrant up

This creates a VM running with IP

More information

In this post, we’ve demonstrated how to install the public preview release of
SQL Server on Ubuntu. Microsoft also provides support for other Linux
distributions, such as Red Hat and Suse.

You can also install this new SQL Server preview on Windows, macOS, Azure or
using a preconfigured Docker container.

Get more information on SQL Server for Linux from the official website.
Find specific information on how to use SQL Server with PHP

Source: Zend feed

Using Laravel Homestead with Zend Framework Projects

Laravel Homestead is an interesting
project by the Laravel community that provides a Vagrant
box for PHP developers. It includes a full set of services for PHP developers,
such as the Nginx web server, PHP 7.1, MySQL, Postgres, Redis, Memcached, Node, and

One the most interesting features of this project is the ability to enable it per
project. This means you can run a vagrant box for your specific PHP project.

In this post, we’ll examine using it for Zend Framework MVC, Expressive, and
Apigility projects. In each case, installation and usage is exactly the same.

Install the Vagrant box

The first step is to install the laravel/homestead
vagrant box. This box works with a variety of providers: VirtualBox 5.1,
VMWare, or Parallels.

We used VirtualBox and the following command to install the laravel/homestead

$ vagrant box add laravel/homestead

The box is 981 MB, so it will take some minutes to download.

Homestead, by default, uses the host name homestead.app, and requires that you
update your system hosts file to point that domain to the virtual machine IP
address. To faciliate that, Homestead provides integration with the
Vagrant plugin. We recommend installing that before your initial run of the
virtual machine:

$ vagrant plugin install vagrant-hostsupdater

Use Homestead in ZF projects

Once you have installed the laravel/homestead vagrant box, you can use it globally
or per project.

If we install Homestead per-project, we will have a full development server
configured directly in the local folder, without sharing services with other
projects. This is a big plus!

To use Homestead per-project, we need to install the laravel/homestead
package within our Zend Framework, Apigility, or Expressive project. This can be
done using Composer with the following command:

$ composer require --dev laravel/homestead

After installation, execute the homestead command to build the Vagrantfile:

$ vendor/bin/homestead make

This command creates both the VagrantFile and a Homestead.yaml configuration

Configuring Homestead

By default, the vagrant box is set up at address with the hostname
homestead.app. You can change the IP address in Homestead.yaml if you want,
as well as the hostname (via the sites[].map key).

The Homestead.yaml configuration file contains all details about the
vagrant box configuration. The following is an example:

ip: ""
memory: 2048
cpus: 1
hostname: expressive-homestead
name: expressive-homestead
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

    - ~/.ssh/id_rsa

    - map: "/home/enrico/expressive-homestead"
      to: "/home/vagrant/expressive-homestead"

    - map: homestead.app
      to: "/home/vagrant/expressive-homestead/public"

    - homestead

This configuration file is very simple and intuitive; for instance, the folders
to be used are reported in the folders section; the map value is the local
folder of the project, the to value is the folder on the virtual machine.

If you want to add or change more features in the virtual machine you can used
the Homestead.yaml configuration file. For instance, if you prefer to add
MariaDB instead of MySQL, you need to add the mariadb option:

ip: ""
memory: 2048
cpus: 1
hostname: expressive-homestead
name: expressive-homestead
provider: virtualbox
mariadb: true

This option will remove MySQL and install MariaDB.

SSH keys managed by GPG

One of our team uses the gpg-agent as an ssh-agent, which caused some
configuration problems initially, as the ~/.ssh/id_rsa and its .pub
sibling were not present.

When using gpg-agent for serving SSH keys, you can export the key using
ssh-add -L. This may list several keys, but you should be able to find the
correct one. Copy it to the file ~/.ssh/gpg_key.pub, and then copy that file
to ~/.ssh/gpg_key.pub.pub. Update the Homestead.yaml file to reflect
these new files:

authorize: ~/.ssh/gpg_key.pub.pub
    - ~/.ssh/gpg_key.pub

The gpg-agent will take care of sending the appropriate key from there.

Running Homestead

To run the vagrant box, execute the following within your project root:

$ vagrant up

If you open a browser to http://homestead.app you should now see your
application running.

Manually managing your hosts file

If you chose not to use vagrant-hostsupdater, you will need to update your
system hosts file.

On Linux and Mac, update the /etc/hosts file to add the following line: homestead.app

On Windows, the host file is located in C:WindowsSystem32driversetchosts.

More information

We’ve tested this setup with each of the Zend Framework zend-mvc skeleton
application, Apigility, and Expressive, and found the setup "just worked"! We
feel it provides excellent flexibility in setting up development environments,
giving developers a wide range of tools and technologies to work with as they
develop applications.

For more information about Laravel Homestead, visit the
official documentation
of the project.

Source: Zend feed

1 2