Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Build application Using PHP 5.4 – 5.6 Features

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on October 12, 2014

zf2-zendframework2Zend Framework 2 ( 2.3.3 ) requires PHP 5.3.23 or above. If we use PHP 5.4 or above, we can use their features when building module(s). There are many feature, I will only show you some of them that are useful.

1. PHP 5.4 features

a. Traits
ZF2 have several component that provide traits that ready to be used in our application. For example : Zend\EventManager\EventManagerAwareTrait. Instead of implements Zend\EventManager\EventManagerInterface, we can just use this traits.
This is the old way :

namespace Sample\Model;

use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;

class Foo implements EventManagerAwareInterface
{
    protected $events;
    
    public function setEventManager(EventManagerInterface $events)
    {
        $this->events = $events;
        return $this;
    }
    
    public function getEventManager()
    {
        if (!$this->events) {
            $this->setEventManager(new EventManager(__CLASS__));
        }
        
        return $this->events;
    }
    
    public function bar($baz, $bat = null)
    {
        $params = compact('baz', 'bat');
        $this->getEventManager()->trigger(__FUNCTION__, $this, $params);
    }
}

This is the new way :

namespace Sample\Model;

use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerAwareTrait;

class Foo implements EventManagerAwareInterface
{
    use EventManagerAwareTrait;
    
    public function bar($baz, $bat = null)
    {
        $params = compact('baz', 'bat');
        $this->getEventManager()->trigger(__FUNCTION__, $this, $params);
    }
}

Why not extends ? Because extends feature can already been used, and we need another things to be used, for example in the form class that already extends Zend\Form.
We can use many trait in one class.

b. Short array syntax
This is my favourite feature from PHP 5.4 that change array() to []. Lesser code that well be used.
This is the old way :

return array(    
    'router' => array(
        'routes' => array(
           'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
    // ... 
);

This is the new way :

return [
    'router' => [
        'routes' => [
            'home' => [
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    // ...
];

You don’t want to manually change existing project ? You can use this tool to convert everything : https://github.com/thomasbachem/php-short-array-syntax-converter .

c. array dereferencing
In old way, when you want to access value of array from function that return array, you need to make it variable first.
For example, when you want to use one of config file.
This is the old way :

$config = $this->getServiceLocator()->get('Config');
echo $config['myconfig'];

This is the new way :

$myconfig = $this->getServiceLocator()->get('Config')['myconfig'];

d. Closures now support $this.
This is the old way : ( grabbed from https://mwop.net/blog/2012-07-30-the-new-init.html )

public function setEventManager(EventManagerInterface $events)
{
    parent::setEventManager($events);
    $controller =  $this;
    
    $events->attach('dispatch', function ($e) use ($controller) {
        $request = $e->getRequest();
        $method = $request->getMethod();
        
        if (!in_array($method, array('PUT', 'DELETE', 'PATCH'))) {
            // nothing to do
            return;
        }
        
        if ($controller->params()->fromRoute('id', false)) {
            // nothing to do
            return;
        }
        
        // Missing identifier! Redirect.
        return $controller->redirect()->toRoute(/* ... */);
    }, 100); // execute before executing action logic
}

This is the new way :
Now, we don’t need to pass $this that assigned to variable anymore, just use it inside the closure.

public function setEventManager(EventManagerInterface $events)
{
    parent::setEventManager($events);
    
    $events->attach('dispatch', function ($e)  {
        $request = $e->getRequest();
        $method = $request->getMethod();
        
        if (!in_array($method, ['PUT', 'DELETE', 'PATCH'])) {
            // nothing to do
            return;
        }
        
        if ($this->params()->fromRoute('id', false)) {
            // nothing to do
            return;
        }
        
        // Missing identifier! Redirect.
        return $this->redirect()->toRoute(/* ... */);
    }, 100); // execute before executing action logic
}

e. Class member access on instantiation has been added
This is the old way :

use Zend\Db\TableGateway\TableGateway;
$selectedtable = new TableGateway('tableneedtobeselected', $adapterSelect);
$select = $selectedtable->getSql()->select()->where(array('field' => 'value'));

This is the new way :

use Zend\Db\TableGateway\TableGateway;
$select = (new TableGateway('tableneedtobeselected', $adapterSelect))
    ->getSql()->select()->where(['field' => 'value']);

2. PHP 5.5 features

a. Class name resolution via ::class
It is very useful when we call service that has name same as its Namespace\ClassName.
This is the old way :

$serviceLocator->get('My\Very\Long\Service\Name');

This is the new way :

use My\Very\Long\Service\Name;
$serviceLocator->get(Name::class);

It will reduce of re-type long servicename when the service call many times in our file, for example : in tests file. It will be useful when we want to call full class name in our module.config.php like the following :

use Application\Controller\IndexController;

return[
    'router' => [
        'routes' => [
            'home' => [
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => IndexController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    
    'controllers' => [
        'invokables' => [
            IndexController::class => IndexController::class
        ],
    ],
    
    // ...
];

b. finally keyword
Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.

try{
    $adapter->getDriver()->getConnection()->beginTransaction();
    
    $adapter->query("INSERT INTO album(artist, title) values('Ray', 'Love')")->execute();
    $lastInsertedId = $this->getAdapter()->getDriver()->getConnection()->getLastGeneratedValue(); 
    $adapter->query("INSERT INTO track(title, album_id) values('New Title', 'Foo')")->execute();
    
    $adapter->getDriver()->getConnection()->commit();
} catch(\Exception $e) {
    $adapter->getDriver()->getConnection()->rollback();
    throw $e;
} finally {
    $adapter->getDriver()->getConnection()->disconnect();        
}

3. PHP 5.6 features

Managing function parameters is now easier with Variadic and Argument Unpacking.
This is the old way :

class Bar {}
class Foo
{
    public function __construct(Bar $bar)
    {
        var_dump($bar);
        
        //getting argument list 
        $numargs = func_num_args();
        if ($numargs > 1) {
            $args = func_get_args();
            
            $options = array();
            foreach($args as $key => $row) {
                if ($key > 0 ) {
                    $options[] = $row;
                }
            }
            
            var_dump($options);
        }
    }
}

$foo = new Foo(new Bar, 'a', 'b', 'c', 'd');

This is the new way :

class Bar {}
class Foo
{
    public function __construct(Bar $bar, ...$options)
    {
        var_dump($bar);
        var_dump($options);
    }
}

$foo = new Foo(new Bar, 'a', 'b', 'c', 'd');

We can pack the argument list by : … too.

$options = [
    'a',
    'b',
    'c',
    'd'
];
$foo = new Foo(new Bar, ...$options);

// OR collect all of them in one array

$options = [
    new Bar,
    'a',
    'b',
    'c',
    'd'
];
$foo = new Foo(...$options);

This feature can be useful when managing service dependencies, for example :

namespace MyModule\Factory\Service;

use MyModule\Service\Bar;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class FooServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $options = [
            $serviceLocator->get('Bar'),
            'a',
            'b',
            'c',
            'd',
        ];
        
        $foo = new Foo(...$options);
        return $foo;
    }
}

Ok, I hope my post is useful. What PHP version you’re using ? 🙂

References :

1. http://php.net/manual/en/migration54.new-features.php
2. http://php.net/manual/en/migration55.new-features.php
3. http://php.net/manual/en/migration56.new-features.php
4. https://mwop.net/blog/2012-07-30-the-new-init.html
5. https://github.com/thomasbachem/php-short-array-syntax-converter

4 Responses

Subscribe to comments with RSS.

  1. Kevin Hamilton said, on October 13, 2014 at 3:49 pm

    Excellent post. We are using 5.5 at the moment – I had not realised there are traits already available to be used in ZF2, very good to know I will look into what’s available.

    there is a minor error in “d. Closures now support $this” where on line 15 of the the old way there is a reference to $this that should be $controller.

    Thanks for a great article.

  2. goat said, on November 10, 2014 at 1:04 am

    I think “the new way” for traits should still be “class Foo implements EventManagerAwareInterface”, but just use the trait to fulfill the interface contract.

    Your website is great – It’s been extremely helpful to me while developing with zf2. Thanks!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: