Home Web Development Modular Programming with PHP 7

Modular Programming with PHP 7

By Branko Ajzele
books-svg-icon Book
eBook $43.99
Print $54.99
Subscription $15.99
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $43.99
Print $54.99
Subscription $15.99
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Ecosystem Overview
About this book
Modular design techniques help you build readable, manageable, reusable, and more efficient codes. PHP 7, which is a popular open source scripting language, is used to build modular functions for your software. With this book, you will gain a deep insight into the modular programming paradigm and how to achieve modularity in your PHP code. We start with a brief introduction to the new features of PHP 7, some of which open a door to new concepts used in modular development. With design patterns being at the heart of all modular PHP code, you will learn about the GoF design patterns and how to apply them. You will see how to write code that is easy to maintain and extend over time with the help of the SOLID design principles. Throughout the rest of the book, you will build different working modules of a modern web shop application using the Symfony framework, which will give you a deep understanding of modular application development using PHP 7.
Publication date:
September 2016
Publisher
Packt
Pages
332
ISBN
9781786462954

 

Chapter 1. Ecosystem Overview

It has been more than two decades now since the birth of PHP. Originally created by Rasmus Lerdorf in 1994, the PHP acronym initially stood for Personal Home Page. Back then, PHP was merely a few Common Gateway Interface (CGI) programs in C, used to power a simple web page.

Though PHP was not intended to be a new programming language, the idea caught on. During the late nineties Zeev Suraski and Andi Gutmans, co-founders of Zend Technologies, continued the work on PHP by rewriting its entire parser, giving birth to PHP 3. The PHP language name acronym now stood for PHP: Hypertext Preprocessor.

PHP positions itself among the top ten programming languages in the world. According to TIOBE, the software quality company, it currently holds sixth place. For the last decade, especially since the release of PHP 5 in July 2004, PHP has been recognized as the popular solution for building web applications.

Though PHP still presents itself as a scripting language, it's safe to say that as of PHP 5 it is far more than that. Some of the world web's most popular platforms like WordPress, Drupal, Magento, and PrestaShop are built in PHP. It is projects like these that played a role in further raising the popularity of PHP. Some of them stretch the boundaries of PHP by implementing complex OOP (Object Oriented Programming) design patterns found in other programming languages like Java, C#, and their frameworks.

Even though PHP 5 had decent OOP support, lots of things were still left to be dreamed of. Work on PHP 6 was planned to give more support for the PHP Unicode strings. Sadly, its development came to a halt and PHP 6 was canceled in 2010.

That same year, Facebook announced its HipHop compiler. Their compiler was converting PHP code into C++ code. The C++ code was further compiled into native machine code via a C++ compiler. This concept brought major performance improvements for PHP. However, this approach was not very practical, because it took too long to compile PHP scripts all the way to native machine code.

Shortly after, Dmitry Stogov, Zend Technologies Chief Performance Engineer, announced a project called PHPNG, which became the basis for the next PHP version, PHP 7.

In Dec 2015, PHP 7 was released, bringing numerous improvements and new features:

  • New version of the Zend Engine

  • Improved performance (twice as fast as PHP 5.6)

  • Significantly reduced memory usage

  • Abstract Syntax Tree

  • Consistent 64-bit support

  • Improved exception hierarchy

  • Many fatal errors converted to exceptions

  • Secure random number generator

  • Removed old and unsupported SAPIs and extensions

  • The null coalescing operator

  • Return and Scalar type declarations

  • Anonymous classes

  • Zero cost asserts

In this chapter, we will look at the following topics:

  • Getting ready for PHP 7

  • Frameworks

 

Getting ready for PHP 7


PHP 7 comes with quite a big list of changes. These changes affect both the PHP interpreter and the various extensions and libraries. Though most of the PHP 5 code will continue to operate normally on the PHP 7 interpreter, it is worth getting up to speed with the newly available features.

Moving forward, we will look into some of these features and the benefits they provide.

Scalar type hints

Scalar type hints are not an entirely new feature in PHP. With the introduction of PHP 5.0 we were given the ability to type hint classes and interfaces. PHP 5.1 extended this by introducing array type hinting. Later on, with PHP 5.4, we were additionally given the ability to type hint callable. Finally, PHP 7 introduced scalar type hints. Extending the type hints to scalars makes this probably one of the most exciting features added to PHP 7.

The following scalar type hints are now available:

  • string: Strings (for example, hello, foo, and bar)

  • int: Integer numbers (for example, 1, 2, and 3)

  • float: Floating point numbers (for example, 1.2, 2.4, and 5.6)

  • bool: Boolean values (for example, true or false)

By default, PHP 7 works in weak type-checking mode, and will attempt to convert to the specified type without complaint. We can control this mode using the strict_typesdeclare() directive.

The declare(strict_types=1); directive must be the first statement in a file, or else it will generate a compiler error. It only affects the specific file it is used in, and does not affect other included files. The directive is entirely compile-time and cannot be controlled at runtime:

declare(strict_types=0); //weak type-checking
declare(strict_types=1); // strict type-checking

Let's assume the following simple function that accepts hinted scalar types.

function hint (int $A, float $B, string $C, bool $D)
{
    var_dump($A, $B, $C, $D);
}

The weak type-checking rules for the new scalar type declarations are mostly the same as those of extensions and built-in PHP functions. Because of this automated conversion we might unknowingly lose data when passing it into a function. One simple example is passing a float into a function that requires an int; in which case conversion would simply strip away decimals.

Assuming the weak type-checking is on, as by default, the following can be observed:

hint(2, 4.6, 'false', true); 
/* int(2) float(4.6) string(5) "false" bool(true) */

hint(2.4, 4, true, 8);
/* int(2) float(4) string(1) "1" bool(true) */

We can see that the first function call passes on parameters as they are hinted. The second function call does not pass the exact types of parameters but still the function manages to execute as parameters go through conversion.

Assuming the weak type-checking is off, by using the declare(strict_types=1); directive, the following can be observed:

hint(2.4, 4, true, 8);

Fatal error: Uncaught TypeError: Argument 1 passed to hint() must be of the type integer, float given, called in php7.php on line 16 and defined in php7.php:8 Stack trace: #0 php7.php(16): hint(2.4, 4, true, 8) #1 {main} thrown in php7.php on line 8

The function call broke on the first argument resulting in the \TypeError exception. The strict_types=1 directive does not allow any type juggling. The parameter has to be of the same type, as hinted by the function definition.

Return type hints

In addition to type hinting, we can also type hint the return values. All of the type hints that can be applied to function parameters can be applied to function return values. This also implies to the weak type-checking rules.

To add a return type hint, simply follow the parameter list with a colon and the return type, as shown in the following example:

function divide(int $A, int $B) : int
{
    return $A / $B;
}

The preceding function definition says that the divide function expects two parameters of the int type, and is supposed to return a parameter of the int type.

Assuming the weak type-checking is on, as by default, the following can be observed:

var_dump(divide(10, 2)); // int(5)
var_dump(divide(10, 3)); // int(3)

Though the actual result of divide(10, 3)should be a float, the return type hint triggers conversion into an integer.

Assuming the weak type-checking is off, by using the declare(strict_types=1); directive, the following can be observed:

int(5) 
Fatal error: Uncaught TypeError: Return value of divide() must be of the type integer, float returned in php7.php:10 Stack trace: #0php7.php(14): divide(10, 3) #1 {main} thrown in php7.php on line 10

With the strict_types=1 directive in place, the divide(10, 3) fails with the \TypeError exception.

Tip

Using scalar type hints and return type hints can improve our code readability as well as auto-complete features of IDE editors like NetBeans and PhpStorm.

Anonymous classes

With the addition of anonymous classes, PHP objects gained closure-like capabilities. We can now instantiate objects through nameless classes, which brings us closer to object literal syntax found in other languages. Let's take a look at the following simple example:

$object = new class {
    public function hello($message) {
        return "Hello $message";
    }
};

echo$object->hello('PHP');

The preceding example shows an $object variable storing a reference to an instance of an anonymous class. The more likely usage would be to directly pass the new class to a function parameter, without storing it as a variable, as shown here:

$helper->sayHello(new class {
    public function hello($message) {
        return "Hello $message";
    }
});

Similar to any normal class, anonymous classes can pass arguments through to their constructors, extend other classes, implement interfaces, and use traits:

class TheClass {}
interface TheInterface {}
trait TheTrait {}

$object = new class('A', 'B', 'C') extends TheClass implements TheInterface {

    use TheTrait;

    public $A;
    private $B;
    protected $C;

    public function __construct($A, $B, $C)
    {
        $this->A = $A;
        $this->B = $B;
        $this->C = $C;
    }
};

var_dump($object);

The above example would output:

object(class@anonymous)#1 (3) { ["A"]=> string(1) "A"["B":"class@anonymous":private]=> string(1) "B"["C":protected]=> string(1) "C" }

The internal name of an anonymous class is generated with a unique reference based on its address.

There is no definitive answer as to when to use anonymous classes. It depends almost entirely on the application we are building, and the objects, depending on their perspective and usage.

Some of the benefits of using anonymous classes are as follows:

  • Mocking application tests becomes trivial. We can create on-the-fly implementations for interfaces, avoiding using complex mocking APIs.

  • Avoid invoking the autoloader every so often for simpler implementations.

  • Makes it clear to anyone reading the code that this class is used here and nowhere else.

Anonymous classes, or rather objects instantiated from anonymous classes, cannot be serialized. Trying to serialize them results in a fatal error as follows:

Fatal error: Uncaught Exception: Serialization of 'class@anonymous' is not allowed in php7.php:29 Stack trace: #0 php7.php(29): serialize(Object(class@anonymous)) #1 {main} thrown in php7.php on line 29

Nesting an anonymous class does not give it access to private or protected methods and properties of the outer class. In order to use the outer class protected methods and properties, the anonymous class can extend the outer class. Ignoring methods, private or protected properties of the outer class can be used in the anonymous class if passed through its constructor:

class Outer
{
    private $prop = 1;
    protected $prop2 = 2;

    protected function outerFunc1()
    {
        return 3;
    }

    public function outerFunc2()
    {
        return new class($this->prop) extends Outer
        {
            private $prop3;

            public function __construct($prop)
            {
                $this->prop3 = $prop;
            }

            public function innerFunc1()
            {
                return $this->prop2 + $this->prop3 + $this->outerFunc1();
            }
        };
    }
}

echo (new Outer)->outerFunc2()->innerFunc1(); //6

Though we labeled them as anonymous classes, they are not really anonymous in terms of the internal name the PHP engine assigns to objects instantiated from these classes. The internal name of an anonymous class is generated with a unique reference based on its address.

The statement get_class(new class{}); would result in something like class@anonymous/php7.php0x7f33c22381c8, where 0x7f33c22381c8 is the internal address. If we were to define the exact same anonymous class elsewhere in the code, its class name would be different as it would have a different memory address assigned. The resulting object in that case might have the same property values, which means they will be equal (==) but not identical (===).

The Closure::call() method

PHP introduced the Closure class in the 5.3 version. Closure class is used to represent anonymous functions. Anonymous functions, implemented in PHP 5.3, yield objects of this type. As of PHP 5.4, the Closure class got several methods (bind, bindTo) that allow further control of the anonymous function after it has been created. These methods basically duplicate the Closure with a specific bound object and class scope. PHP 7 introduced the call method on a Closure class. The call method does not duplicate the closure, it temporarily binds the closure to new this ($newThis), and calls it with any given parameters. It then returns the return value of the closure.

The call function signature looks like the following:

function call ($newThis, ...$parameters) {}

$newThis is the object to bind the closure for the duration of the call. The parameters, which will be given as $parameters to the closure are optional, meaning zero or more.

Let's take a look at the following example of a simple Customer class and a $greeting closure:

class Customer {
    private $firstname;
    private $lastname;

    public function __construct($firstname, $lastname)
    {
        $this->firstname = $firstname;
        $this->lastname = $lastname;
    }
}

$customer = new Customer('John', 'Doe');

$greeting = function ($message) {
    return "$message $this->firstname $this->lastname!";
};

echo $greeting->call($customer, 'Hello');

Within the actual $greeting closure, there is no $this, it does not exist until the actual binding occurs. We could easily confirm this by directly calling a closure like $greeting('Hello');. However, we assume $this will come in to existence when we bind the closure to a given object instance via its call function. In which case, $this within the closure becomes $this of the customer object instance. The preceding example shows binding of $customer to the closure using a call method call. The resulting output displays Hello John Doe!

Generator delegation

Generators provide a simple way to implement iterators without the overhead of implementing a class that implements the Iterator interface. They allow us to write code which uses foreach to iterate over a set of data without needing to build an array in memory. This eliminates the exceeds memory limit errors. They were not new to PHP, as they were added in PHP 5.5.

However, PHP 7 brings several new improvements to generators, one of which is generator delegation.

Generator delegation allows a generator to yield other generators, arrays, or objects that implement the Traversable interface. In another words, we might say that generator delegation is yielding subgenerators.

Let's take a look at the following example with three generator type functions:

function gen1() {
    yield '1';
    yield '2';
    yield '3';
}

function gen2() {
    yield '4';
    yield '5';
    yield '6';
}

function gen3() {
    yield '7';
    yield '8';
    yield from gen1();
    yield '9';
    yield from gen2();
    yield '10';
}

// output of the below code: 123
foreach (gen1() as $number) {
echo $number;
}

//output of the below code: 78123945610
foreach (gen3() as $number) {
    echo $number;
}

Yielding other generators requires using the yield from <expression> syntax.

Generator return expressions

Prior to PHP 7, generator functions were not able to return expressions. The inability of generator functions to specify return values limited their usefulness for multitasking in co-routine contexts.

PHP 7 made it possible for generators to return expressions. We can now call $generator->getReturn() to retrieve the return expression. Calling $generator->getReturn() when the generator has not yet returned, or has thrown an uncaught exception, will throw an exception.

If the generator has no return expression defined and has completed yielding, null is returned.

Let's take a look at the following example:

function gen() {
    yield 'A';
    yield 'B';
    yield 'C';

    return 'gen-return';
}

$generator = gen();

//output of the below code: object(Generator)#1 (0) { }
var_dump($generator);

// output of the below code: Fatal error
// var_dump($generator->getReturn());

// output of the below code: ABC
foreach ($generator as $letter) {
    echo $letter;
}

// string(10) "gen-return"
var_dump($generator->getReturn());

Looking at the gen() function definition and its return expression, one might expect the value of the $generator variable to be equal to the gen-return string. However, this is not the case, as the $generator variable becomes the instance of the \Generator class. Calling the getReturn() method on the generator while it is still open (not iterated over) will result in a fatal error.

If the code is structured in such a way that it is not obvious if the generator has been closed, we can use the valid method to check, before fetching the return value:

if ($generator->valid() === false) {
    var_dump($generator->getReturn());
}

The null coalesce operator

In PHP 5 we had the ternary operator which tests a value and then returns the second element if that value is true, or third element if that value is false, as shown in the following code block:

$check = (5 > 3) ? 'Correct!' : 'Faulty!'; // Correct!
$check = (5 < 3) ? 'Correct!' : 'Faulty!'; // Faulty!

While processing user-provided data in web-centered languages such as PHP, it is common to check for variable existence. If a variable doesn't exist, then set it to some default value. A ternary operator makes this easy for us, as shown here:

$role = isset($_GET['role']) ? $_GET['role'] : 'guest';

However, easy is not always quick or elegant. With that in mind, PHP 7 set out to resolve one of the most common usage patterns, by introducing the null coalesce operator(??).

The null coalesce operator enables us to write even shorter expressions, as in the following code block:

$role = $_GET['role'] ??'guest';

The coalesce operator(??) is added right after the $_GET['role'] variable, which returns the result of its first operand if it exists and is not NULL, or else its second operand. This means the $_GET['role'] ?? 'guest' is completely safe and will not raise an E_NOTICE.

We can also nest the coalesce operator:

$A = null; // or not set
$B = 10;

echo $A ?? 20; // 20
echo $A ?? $B ?? 30; // 10

Reading from left to right, the first value which exists and is not null is the value that will be returned. The benefit of this construct is that it enables a clean and effective way to achieve safe fallback to the desired value.

Tip

The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Modular-Programming-with-PHP7. We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

The Spaceship operator

The three-way comparison operator, also known as the Spaceship operator, was introduced in PHP 7. Its syntax goes as follows:

(expr) <=> (expr)

The operator returns 0 if both operands are equal, 1 if the left is greater, and -1 if the right is greater.

It uses the same comparison rules as other existing comparison operators: <, <=, ==, >=, and >:

operator<=> equivalent
$a < $b($a <=> $b) === -1
$a <= $b($a <=> $b) === -1 || ($a <=> $b) === 0
$a == $b($a <=> $b) === 0
$a != $b($a <=> $b) !== 0
$a >= $b($a <=> $b) === 1 || ($a <=> $b) === 0
$a > $b($a <=> $b) === 1

The following are some examples of Spaceship operator behavior:

// Floats
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// Strings
echo "a"<=>"a"; // 0
echo "a"<=>"b"; // -1
echo "b"<=>"a"; // 1

echo "a"<=>"aa"; // -1
echo "zz"<=>"aa"; // 1

// Arrays
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

// Objects
$a = (object) ["a" =>"b"]; 
$b = (object) ["a" =>"b"]; 
echo $a <=> $b; // 0

$a = (object) ["a" =>"b"]; 
$b = (object) ["a" =>"c"]; 
echo $a <=> $b; // -1

$a = (object) ["a" =>"c"]; 
$b = (object) ["a" =>"b"]; 
echo $a <=> $b; // 1

// only values are compared
$a = (object) ["a" =>"b"]; 
$b = (object) ["b" =>"b"]; 
echo $a <=> $b; // 0

One practical use case for this operator is for writing callbacks used in sorting functions like usort, uasort, and uksort:

$letters = ['D', 'B', 'A', 'C', 'E'];

usort($letters, function($a, $b) {
return $a <=> $b;
});

var_dump($letters);

// array(5) { [0]=> string(1) "A" [1]=> string(1) "B" [2]=>string(1) "C" [3]=> string(1) "D" [4]=> string(1) "E" }

Throwables

Though PHP 5 introduced the exception model, overall errors and error handling remained somewhat unpolished. Basically PHP had two error handling systems. Traditional errors still popped out and were not handled by try…catch blocks.

Take the following E_RECOVERABLE_ERROR as an example:

class Address
{
    private $customer;
    public function __construct(Customer $customer)
    {
        $this->customer = $customer;
    }
}

$customer = new stdClass();

try {
    $address = new Address($customer);
} catch (\Exception $e) {
    echo 'handling';
} finally {
echo 'cleanup';
}

The try…catch block has no effect here, as the error is not interpreted as an exception, rather a catchable fatal error:

Catchable fatal error: Argument 1 passed to Address::__construct() must be an instance of Customer, instance of stdClass given, called in script.php on line 15 and defined in script.php on line 6.

A possible workaround involves setting a user-defined error handler by using the set_error_handler function as follows:

set_error_handler(function($code, $message) {
    throw new \Exception($message, $code);
});

The error handler, as written above, would now transform every error into an exception, therefore making it catchable with try…catch blocks.

PHP 7 made fatal and catchable fatal errors part of engine exceptions, therefore catchable with try…catch blocks. This excludes warnings and notices which still do not pass through the exception system, which makes sense for backward compatibility reasons.

It also introduced a new exception hierarchy via the \Throwable interface. \Exception and \Error implement the \Throwable interface.

Standard PHP fatal and catchable fatal are now thrown as \Error exceptions, though they will continue to trigger traditional fatal error if they are uncaught.

Throughout our application we must use \Exception and \Error, as we cannot implement the \Throwable interface directly. We could, however, use the following block to catch all errors, regardless of whether it is the \Exception or \Error type:

try {
// statements
} catch (\Throwable $t) {
    // handling
} finally {
// cleanup
}

The \ParseError

The ParseError is a nice PHP 7 addition to error handling. We can now handle parse errors triggered by eval(), include and require statements, as well as those thrown by \ParseError exceptions. It extends \Error, which in turn implements a \Throwable interface.

The following is an example of a broken PHP file, because of a missing "," inbetween between array items:

<?php

$config = [
'host' =>'localhost'
'user' =>'john'
];

return $config;

The following is an example of a file including config.php:

<?php 

try {
include 'config.php';
} catch (\ParseError $e) {
// handle broken file case
}

We can now safely catch possible parse errors.

Level support for the dirname() function

The dirname function has been with us since PHP 4. It's probably one of the most often used functions in PHP. Up until PHP 7, this function only accepted the path parameter. With PHP 7, the new levels parameter was added.

Let's take a look at the following example:

// would echo '/var/www/html/app/etc'
echo dirname('/var/www/html/app/etc/config/');

// would echo '/var/www/html/app/etc'
echo dirname('/var/www/html/app/etc/config.php');

// would echo '/var/www/html/app'
echo dirname('/var/www/html/app/etc/config.php', 2);

// would echo '/var/www/html'
echo dirname('/var/www/html/app/etc/config.php', 3);

By assigning the levels value, we indicate how many levels to go up from the assigned path value. Though small, the addition of the levels parameter will certainly make it easier to write some of the code that deals with paths.

The integer division function

The intdiv is a new integer division function introduced in PHP 7. The function accepts dividend and divisor as parameters and returns the integer quotient of their division, as shown here by the function description:

int intdiv(int $dividend, int $divisor)

Let's take a look at the following few examples:

intdiv(5, 3); // int(1)
intdiv(-5, 3); // int(-1)
intdiv(5, -2); // int(-2)
intdiv(-5, -2); // int(2)
intdiv(PHP_INT_MAX, PHP_INT_MAX); // int(1)
intdiv(PHP_INT_MIN, PHP_INT_MIN); // int(1)

// following two throw error
intdiv(PHP_INT_MIN, -1); // ArithmeticError
intdiv(1, 0); // DivisionByZeroError

If the dividend is PHP_INT_MIN and the divisor is -1, then an ArithmeticError exception is thrown. If the divisor is 0, then the DivisionByZeroError exception is thrown.

Constant arrays

Prior to PHP 7, constants defined with define() could only contain scalar expressions, but not arrays. As of PHP 5.6, it is possible to define an array constant by using const keywords, and as of PHP 7, array constants can also be defined using define():

// the define() example
define('FRAMEWORK', [
'version' => 1.2,
'licence' =>'enterprise'
]);

echo FRAMEWORK['version']; // 1.2
echo FRAMEWORK['licence']; // enterprise

// the class const example
class App {
    const FRAMEWORK = [
'version' => 1.2,
'licence' =>'enterprise'
    ];
}

echo App::FRAMEWORK['version']; // 1.2
echo App::FRAMEWORK['licence']; // enterprise

Constants may not be redefined or undefined once they have been set.

Uniform variable syntax

To make PHP's parser more complete for various variable dereferences, PHP 7 introduced a uniform variable syntax. With uniform variable syntax all variables are evaluated from left to right.

Unlike various functions, keywords, or settings being removed, changes in semantics like this one can be quite impacting for the existing code base. The following code demonstrates the syntax, its old meaning and new:

// Syntax
$$foo['bar']['baz']
// PHP 5.x:
// Using a multidimensional array value as variable name
${$foo['bar']['baz']}
// PHP 7:
// Accessing a multidimensional array within a variable-variable
($$foo)['bar']['baz']

// Syntax
$foo->$bar['baz']
// PHP 5.x:
// Using an array value as a property name
$foo->{$bar['baz']}
// PHP 7:
// Accessing an array within a variable-property
($foo->$bar)['baz']

// Syntax
$foo->$bar['baz']()
// PHP 5.x:
// Using an array value as a method name
$foo->{$bar['baz']}()
// PHP 7:
// Calling a closure within an array in a variable-property
($foo->$bar)['baz']()

// Syntax
Foo::$bar['baz']()
// PHP 5.x:
// Using an array value as a static method name
Foo::{$bar['baz']}()
// PHP 7:
// Calling a closure within an array in a static variable
(Foo::$bar)['baz']()

Aside from previously rewritten examples of old-to-new syntax, there are now a few newly supported syntax combinations.

PHP 7 now supports nested double colons,::, and following is an example of it:

// Access a static property on a string class name
// or object inside an array
$foo['bar']::$baz;
// Access a static property on a string class name or object
// returned by a static method call on a string class name
// or object
$foo::bar()::$baz;
// Call a static method on a string class or object returned by
// an instance method call
$foo->bar()::baz();

We can also nest methods and function calls—or any callables—by doubling up on parentheses as shown in the following code examples:

// Call a callable returned by a function
foo()();
// Call a callable returned by an instance method
$foo->bar()();
// Call a callable returned by a static method
Foo::bar()();
// Call a callable return another callable
$foo()();

Furthermore, we can now dereference any valid expression enclosed with parentheses:

// Access an array key
(expression)['foo'];
// Access a property
(expression)->foo;
// Call a method
(expression)->foo();
// Access a static property
(expression)::$foo;
// Call a static method
(expression)::foo();
// Call a callable
(expression)();
// Access a character
(expression){0};

Secure random number generator

PHP 7 introduced two new CSPRNG functions. CSPRNG is an acronym for cryptographically secure pseudo-random number generator.

The first, random_bytes, generates an arbitrary length string of cryptographic random bytes that are suitable for cryptographic use, such as when generating salts, keys, or initialization vectors. The function accepts only one (length) parameter, representing the length of the random string that should be returned in bytes. It returns a string containing the requested number of cryptographically secure random bytes, or, optionally, it throws an exception if an appropriate source of randomness cannot be found.

The following is an example of random_bytes usage:

$bytes = random_bytes(5);

The second, random_int, generates cryptographic random integers that are suitable for use where unbiased results are critical, such as when shuffling a deck of cards for a poker game. The function accepts two (min, max) parameters, representing the lowest value to be returned (must be PHP_INT_MIN or higher) and the highest value to be returned (must be less than or equal to PHP_INT_MAX). It returns a cryptographically secure random integer in the range min to max (inclusive).

The following is an example of random_int usage:

$int = random_int(1, 10);
$int = random_int(PHP_INT_MIN, 500);
$int = random_int(20, PHP_INT_MAX);
$int = random_int(PHP_INT_MIN, PHP_INT_MAX);

Filtered unserialize()

Serialized data can include objects. These objects can further include functions like destructors, __toString, and __call. In order to increase security when unserializing objects on unstructured data, PHP 7 introduced the optional options parameter to the existing unserialize function.

The options parameter is of type array that currently only accepts the allowed_classes key.

The allowed_classes can have one of three values:

  • true: This is a default value and allows all objects just as before

  • false: Here no objects allowed

  • array of allowed class names, lists the allowed classes for unserialized objects

The following is an example of using the allowed_classes option:

class Customer{
    public function __construct(){
        echo '__construct';
    }

    public function __destruct(){
        echo '__destruct';
    }

    public function __toString(){
        echo '__toString';
        return '__toString';
    }

    public function __call($name, $arguments) {
        echo '__call';
    }
}

$customer = new Customer();

$s = serialize($customer); // triggers: __construct, __destruct

$u = unserialize($s); // triggers: __destruct
echo get_class($u); // Customer

$u = unserialize($s, ['allowed_classes'=>false]); // does not trigger anything
echo get_class($u); // __PHP_Incomplete_Class

We can see that the object of that class which is not accepted is instantiated as __PHP_Incomplete_Class.

Context sensitive lexer

According to the http://php.net/manual/en/reserved.keywords.php list, PHP has over 60 reserved keywords. These make up for language constructs, like names for properties, methods, constants within classes, interfaces, and traits.

Sometimes these reserved words end up clashing with user defined API declarations.

To resolve the issue, PHP 7.0 introduced the context sensitive lexer. With the context sensitive lexer, we may now use keywords for property, function, and constant names within our code.

The following are a few practical examples related to the impact of context sensitive lexer:

class ReportPool {
    public function include(Report $report) {
//
    }
}

$reportPool = new ReportPool();
$reportPool->include(new Report());

class Collection extends \ArrayAccess, \Countable, \IteratorAggregate {

    public function forEach(callable $callback) {
//
    }

    public function list() {
//
    }

    public static function new(array $items) {
        return new self($items);
    }
}

Collection::new(['var1', 'var2'])
->forEach(function($index, $item){ /* ... */ })
->list();

The only exception being the class keyword, which remains reserved in class constant context, as shown here:

class Customer {
  const class = 'Retail'; // Fatal error
}

Group use declarations

The group use declarations are introduced in PHP 7 as a way to cut verbosities when importing multiple classes from a common namespace. They enable shorthand syntax as follows:

use Library\Group1\Group2\{ ClassA, ClassB, ClassC as Classy };

Let's take a look at the following examples where class names within the same namespace are group used:

// Current use syntax
use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Collections\Expr\Value;
use Doctrine\Common\Collections\Expr\CompositeExpression;

// Group use syntax
use Doctrine\Common\Collections\Expr\{ Comparison, Value, CompositeExpression };

We can also use the group use declarations on part of namespaces, as shown in the following example:

// Current use syntax
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion as Choice;
use Symfony\Component\Console\Question\ConfirmationQuestion;

// Group use syntax
use Symfony\Component\Console\{
  Helper\Table,
  Input\ArrayInput,
  Input\InputInterface,
  Output\NullOutput,
  Output\OutputInterface,
  Question\Question,
  Question\ChoiceQuestion as Choice,
  Question\ConfirmationQuestion,
};

We can further use group use for importing functions and constants as shown in the following lines of code:

use Framework\Component\{
SubComponent\ClassA,
function OtherComponent\someFunction,
const OtherComponent\SOME_CONSTANT
};

Unicode enhancements

Unicode, and UTF-8 in particular, have grown increasingly popular in PHP applications.

PHP 7 adds the new escape sequence for double-quoted strings and heredocs, with the syntax as follows:

\u{code-point}

It produces the UTF-8 encoding of a Unicode code point, specified with hexadecimal digits. It is worth noting that the length of the code-point within curly braces is arbitrary. This means that we can use \u{FF} or the more traditional \u{00FF}.

The following is a simple listing of the four most traded currencies, their symbols, and their UTF-8 code points:

Euro€U+20AC
Japanese Yen¥U+00A5
Pound sterling£U+00A3
Australian dollar$U+0024

Some of these symbols usually exist directly on a keyboard, so it's easy to write them down as shown here:

echo "the € currency";
echo "the ¥ currency";
echo "the £ currency";
echo "the $ currency";

However, the majority of other symbols are not as easily accessible via the keyboard as single keystrokes, and therefore need to be written in the form of code-points, shown as follows:

echo "the \u{1F632} face";
echo "the \u{1F609} face";
echo "the \u{1F60F} face";

In older versions of PHP, the resulting output of preceding statements would be the following:

the \u{1F632} face
the \u{1F609} face
the \u{1F60F} face

This obviously did not parse code-points, as it was outputting them literally.

PHP 7 introduced Unicode code-point escape sequence syntax to string literals, making previous statements result in the following output:

the 😉 face
the 😉 face
the 😉 face

Assertions

Assertions is a debug feature, used to check the given assertion and take appropriate action if its result is false. They have been part of PHP for years, ever since PHP 4.

Assertions differ from error handling in a way that assertions cover for impossible cases, whereas errors are possible and need to be handled.

Using assertions as a general-purpose error handling mechanism should be avoided. Assertions do not allow for recovery from errors. Assertion failure will normally halt the execution of a program.

With modern debugging tools like Xdebug, not many developers use assertions for debugging.

Assertions can be easily enabled and disabled using the assert_options function or the assert.active INI setting.

To use assertions, we pass in either an expression or a string as shown in the following function signature:

// PHP 5
bool assert ( mixed $assertion [, string $description ] )

// PHP 7
bool assert ( mixed $assertion [, Throwable $exception ] )

These two signatures differ in the second parameter. PHP 7 can accept either string $description or $exception.

If the expression result or the result of evaluating the string evaluates to false, then a warning is raised. If the second parameter is passed as $exception, then an exception will be thrown instead of failure.

In regards to php.ini configuration options, the assert function has been expanded to allow for so-called zero-cost assertions:

zend.assertions = 1 // Enable
zend.assertions = 0 // Disable
zend.assertions = -1 // Zero-cost

With zero-cost settings, assertions have zero impact on performance and execution as they are not compiled.

Finally, the Boolean assert.exception option was added to the INI setting. Setting it to true, results in AssertionError exceptions for the failed assertions.

Changes to the list() construct

In PHP 5, list() assigns the values starting with the right-most parameter. In PHP 7, list() starts with the left-most parameter. Basically, values are now assigned to variables in the order they are defined.

However, this only affects the case where list() is being used in conjunction with the array [] operator, as discussed in the following code block:

<?php

list($color1, $color2, $color3) = ['green', 'yellow', 'blue'];
var_dump($color1, $color2, $color3);

list($colors[], $colors[], $colors[]) = ['green', 'yellow', 'blue'];
var_dump($colors);

Output of the preceding code in PHP 5 would result in the following:

string(5) "green"
string(6) "yellow"
string(4) "blue"

array(3) { 
[0]=> string(5) "blue"
[1]=> string(6) "yellow"
[2]=> string(4) "green"
}

Output of the preceding code in PHP 7 would result in the following:

string(5) "green"
string(6) "yellow"
string(4) "blue"

array(3) { 
[0]=> string(5) "green"
[1]=> string(6) "yellow"
[2]=> string(4) "blue"
}

The order of assignment might change again in the future, so we should not rely heavily on it.

Session options

Prior to PHP 7, the session_start() function did not directly accept any configuration options. Any configuration options we wanted to set on the session, needed to come from php.ini:

// PHP 5
ini_set('session.name', 'THEAPP');
ini_set('session.cookie_lifetime', 3600);
ini_set('session.cookie_httponly', 1);
session_start();

// PHP 7
session_start([
'name' =>'THEAPP',
'cookie_lifetime' => 3600,
'cookie_httponly' => 1
]);

Driven by the goal of performance optimization, a new lazy_write runtime configuration was added in PHP 7. When lazy_write is set to 1, the session data is only rewritten if it changes. This is the default behavior:

session_start([
'name' =>'THEAPP',
'cookie_lifetime' => 3600,
'cookie_httponly' => 1,
'lazy_write' => 1
]);

While changes listed here might not look impressive at first, being able to override session options directly via the session_start function gives certain flexibility to our code.

Deprecated features

Globally accepted, major versions of software have the luxury of breaking backward compatibility. Ideally, not much, but in order to keep the software moving forward, some old ideas need to be left behind. These changes don't come overnight. Certain features are first flagged as deprecated to warn developers that it will be removed in future versions of the language. Sometimes this period of deprecation takes years.

Throughout PHP 5.x, a number of features have been marked as deprecated, and in PHP 7.0, they have all been removed.

The POSIX-compatible regular expressions have been deprecated in PHP 5.3, and now completely removed in PHP 7.

The following functions are no longer available for use:

  • ereg_replace

  • ereg

  • eregi_replace

  • eregi

  • split

  • spliti

  • sql_regcase

We should instead use Perl Compatible Regular Expressions (PCRE). The http://php.net/manual/en/book.pcre.php is a great source of documentation for these functions.

The mysql extension, which had been deprecated in PHP 5.5, has now been removed. None of the mysql_* functions are available anymore. We should instead use the mysqli extension. The good thing is that moving from mysql to mysqli functions is mostly simple, as when adding i to our code, the mysql_* function calls and passes the database handle (returned by mysqli_connect) as the first parameter. The http://php.net/manual/en/book.mysqli.php is a great source of documentation for these functions.

The PHP script and ASP tags are no longer available:

<!-- PHP script tag example -->
<script language="php">
// Code here
</script>

<!-- PHP ASP tag example -->
<%
// Code here
%>
<%=$varToEcho; %>

Frameworks

Application frameworks are a collection of functions, classes, configurations, and conventions all designed to support the development of web applications, services, and APIs. Some applications are embracing an API first approach, whereas server-side REST and SOAP APIs are built via PHP, and client side in other technologies like JavaScript.

When building a web application, we usually have three obvious choices:

  • We can build everything ourselves, from scratch. This way, our development process might be slow, but we can achieve architecture built entirely per our standards. Needless to say, this is a highly unproductive approach.

  • We can use one of the existing frameworks. This way, our development process is fast, but we need to be happy that our application is built on top of other things.

  • We can use one of the existing frameworks but also try to abstract it to the level where our application looks independent of it. This is a painful and slow approach, to say the least. It involves writing numerous adapters, wrappers, interfaces, and so on.

In a nutshell, frameworks are here to make it easier and quicker for us to build our software. A great deal of programming languages out there have popular frameworks. PHP is no exception to this.

Given the popularity of PHP as a go-to web programming language, it is no surprise that dozens of frameworks have sprouted over the years. Choosing the "right" framework is a daunting task, even so more for fresh starters. What is right for one project or a team might not be right for another.

However, there are some general, high level segments each modern framework should encompass. These account for:

  • Modular: It supports modular application development, allowing us to neatly separate our code into functional building blocks, whereas it is built in a modular manner.

  • Secure: It provides various cryptographic and other security tooling expected of a modern web application. Provides seamless support for things like authentication, authorization, and data encryption.

  • Extensible: Manages to easily adopt our application needs, allowing us to extend it according to our application needs.

  • Community: It is actively developed and supported by a vibrant and active community.

  • High performing: Built with performance in mind. Many frameworks brag about performance, but there are many variables to it. We need to be specific as to what we are evaluating here. Measuring cached performance against raw performance is often the misleading evaluation, as caching proxies can be put in front of many frameworks.

  • Enterprise ready: Depending on the type of project at hand, most likely we would want to target a framework which flags itself as enterprise ready. Making us confident enough of running critical and high-usage business applications on top of it.

While it's perfectly alright to code an entire web application in pure PHP without using any framework, the majority of today's projects do use frameworks.

The benefits of using frameworks outweigh the purity of doing it all from scratch. Frameworks are usually well supported and documented, which makes it easier for teams to catch up with libraries, project structure, conventions, and other things.

When it comes to PHP frameworks, it is worth pointing out a few popular ones:

This is by no means a complete or even a popularity sorted list.

Laravel framework

Laravel is released under an MIT license, and can be downloaded from https://laravel.com/.

Aside from the usual routing, controllers, requests, responses, views, and (blade) templates, out of the box Laravel provides a large amount of additional services such as authentication, cache, events, localization, and many others.

Another neat feature of Laravel, is Artisan, the command line tool, that provides a number of useful commands that we can use during development. Artisan can further be extended by writing our own console commands.

Laravel has a pretty active and vibrant community. Its documentation is simple and clear, which makes it easy for newcomers to get started. Furthermore, there is also https://laracasts.com, which extends out beyond Laravel in terms of documentation and other content. Laracasts is a web service providing a series of expert screencasts, some of which are free.

All of these features make Laravel a choice worth evaluating when it comes to the selection of a framework.

Symfony

Symfony is released under an MIT license, and can be downloaded from http://symfony.com.

Over time, Symfony introduced the concept of Long-term Support(LTS) releases. This release process has been adopted as of Symfony 2.2, and strictly followed as of Symfony 2.4. The standard version of Symfony is maintained for eight months. Long-term Support versions are supported for three years.

One other interesting thing about new releases is the time-based release model. All of the new versions of Symfony releases come out every six months: one in May and one in November.

Symfony has great community support via mailing lists, IRC, and StackOverflow. Furthermore, SensioLabs professional support provides a full range of solutions from consulting, training, coaching, to certification.

Lots of Symfony components are used in other web applications and frameworks, such as Laravel, Silex, Drupal 8, Sylius, and others.

What made Symfony such a popular framework is its interoperability. The idea of "Don't lock yourself up within Symfony!" made it popular with developers as it allowed for building applications that precisely meet our needs.

By embracing the "don't reinvent the wheel" philosophy, Symfony itself makes heavy use of existing PHP open-source projects as part of the framework, including:

  • Doctrine (or Propel): Object-relational mapping layer

  • PDO database abstraction layer (Doctrine or Propel)

  • PHPUnit: A unit testing framework

  • Twig: A templating engine

  • Swift Mailer: An e-mail library

Depending on our project needs, we can choose to use a full-stack Symfony framework, the Silex micro-framework, or simply some of the components individually.

Out of the box, Symfony provides a lot of structural ground for new web applications. It does so via its bundle system. Bundles are sort of like micro-applications inside our main application. Within them, the entire app is nicely structured into models, controllers, templates, configuration files, and other building blocks. Being able to fully separate logic from different domains helps us to keep a clean separation of concerns and autonomously develop every single feature of our domain.

Symfony is one of the PHP pioneers when it comes to embracing the dependency injection across the framework, allowing it to achieve decoupled components and to keep high flexibility of code.

Documented, modular, highly flexible, performant, supported, those are the attributes that make Symfony a choice worth evaluating.

Zend Framework

Zend Framework is released under a new BSD license, and can be downloaded from http://framework.zend.com.

Zend Framework features include:

  • Fully object-oriented PHP components

  • Loosely coupled components

  • Extensible MVC supporting layouts and templates

  • Support for multiple database systems MySQL, Oracle, MS SQL, and so on

  • E-mail handling via mbox, Maildir, POP3, and IMAP4

  • Flexible caching system

Aside from a free Zend Framework, Zend Technologies Ltd provides its own commercial version of a PHP stack called Zend Server, and Zend Studio IDE that includes features specifically to integrate with Zend Framework. While Zend Framework is perfectly fine running on any PHP stack, Zend Server is advertised as an optimized solution for running Zend Framework applications.

By its architectural design, Zend Framework is merely a collection of classes. There is no strictly imposed structure our application needs to follow. This is one of the features that makes it so appealing to a certain range of developers. We could either utilize Zend MVC components to create a fully-functional Zend Framework project, or we can simply load the components we need.

The so called full-stack frameworks impose structure, ORM implementations, code-generation, and other fixed things onto your projects. Zend Framework, on the other hand, with its decoupled nature, classifies for a glue type of framework. We can easily glue it to an existing application, or use it to build a new one.

The latest versions of Zend Framework follow the SOLID object oriented design principle. The so called "use-at-will" design allows developers to use whichever components they want.

Though the main driving force behind Zend Framework is Zend Technologies, many other companies have contributed significant features to the framework.

Furthermore, Zend Technologies provides excellent Zend Certified PHP Engineer certifications. Quality community, official company support, education, hosting, and development tools make the Zend Framework choice worth evaluating.

CodeIgniter

CodeIgniter is released under an MIT license, and can be downloaded from https://www.codeigniter.com.

CodeIgniter prides itself in being lightweight. The core system requires only a handful of small libraries, which is not always the case with other frameworks.

The framework uses the simple Model-View-Control approach, allowing for clean separation between logic and presentation. The View layer does not impose any special template language, so it uses native PHP out of the box.

Here are some of the outstanding features of CodeIgniter:

  • Model-View-Control-based system

  • Extremely light weight

  • Full featured database classes with support for several platforms

  • Query builder database support

  • Form and data validation

  • Security and XSS filtering

  • Localization

  • Data encryption

  • Full page caching

  • Unit testing class

  • Search-engine friendly URLs

  • Flexible URI routing

  • Support for hooks and class extensions

  • Large library of helper functions

CodeIgniter has an active community gathered around http://forum.codeigniter.com.

Small footprint, flexibility, exceptional performance, near-zero configuration, and thorough documentation are what makes this framework choice worth evaluating.

CakePHP

CakePHP is released under an MIT license, and can be downloaded from http://cakephp.org.

The CakePHP framework was greatly inspired by Ruby on Rails, using many of its concepts. It values conventions over configuration.

It comes with "batteries included". Most of the things we need for modern web applications are already built-in. Translations, database access, caching, validation, authentication, and much more are all built-in.

Security is another big part of the CakePHP philosophy. CakePHP comes with built-in tools for input validation, CSRF protection, form tampering protection, SQL injection prevention, and XSS prevention, helping us to secure our application.

CakePHP supports a variety of database storage engines, such as MySQL, PostgreSQL, Microsoft SQL Server, and SQLite. The built-in CRUD feature is very handy for database interaction.

It counts on a big community behind it. It also has a big list of plugins, available at http://plugins.cakephp.org.

CakePHP provides a certification exam, whereby developers are tested in their knowledge of the CakePHP framework, MVC principles, and standards used within CakePHP. Certification is geared towards real world scenarios and intimate CakePHP specifics.

Commercial support, consultation, code review, performance analysis, security audits, and even development services are provided by the Cake Development Corporation http://www.cakedc.com. The Cake Development Corporation is the commercial entity behind the framework, established in 2007 by Larry Masters, a founder of CakePHP.

Slim

Slim is released under an MIT license, and can be downloaded from http://www.slimframework.com.

While frameworks with the "batteries included" mindset provide robust libraries, directory structures, and configurations, micro frameworks get us started with a few lines of code.

Micro frameworks usually lack even the basic framework features such as:

  • Authentication and authorization

  • ORM database abstraction

  • Input validation and sanitation

  • Template engine

This limits their use, but also makes them a great tool for rapid prototyping.

Slim supports any PSR-7 HTTP message implementation. An HTTP message is either a request from a client to a server or a response from a server to a client. Slim functions like a dispatcher that receives an HTTP request, invokes an appropriate callback routine, and returns an HTTP response.

The good thing about Slim is that it plays nicely with middleware. The middleware is basically a callable that accepts three arguments:

  • \Psr\Http\Message\ServerRequestInterface: The PSR7 request object

  • \Psr\Http\Message\ResponseInterface: The PSR7 response object

  • callable: The next middleware callable

Middlewares are free to manipulate request and response objects, as long as they return an instance of \Psr\Http\Message\ResponseInterface. Furthermore, each middleware needs to invoke the next middleware and pass it to request and response objects as arguments.

This simple concept gives Slim the power of extensibility, through various possible third party middlewares.

Even though Slim provides good documentation, a vibrant community, and the project is being actively developed to date, its usage is limited. Micro frameworks are hardly a choice for robust enterprise applications. Still, they have their place in development.

Yii

Yii is released under a BSD License, and can be downloaded from http://www.yiiframework.com.

Yii's focus on performance optimization makes it a perfect choice for almost any type of project, including the enterprise type of applications.

Some of the outstanding Yii features include:

  • The MVC design pattern

  • Automatic generation of complex service WSDL

  • Translation, localization, locale-sensitive formatting of dates, time, and numbers

  • Data caching, fragment caching, page caching, and HTTP caching

  • Error handler that displays errors based on the nature of the errors and the mode the application runs in

  • Security measures to help prevent SQL injection, Cross-site scripting (XSS), Cross-site request forgery (CSRF), and cookie tampering

  • Unit and functional testing based on PHPUnit and Selenium

One of the neat features of Yii is a tool called Gii. It's an extension that provides a web-based code generator. We can use Gii's graphical interface to quickly set up generate models, forms, modules, CRUD, and so on. There is also a command line version of Gii for those who prefer consoles over GUI.

Yii's architecture allows it to play nicely with third-party code, like PEAR libraries, Zend Framework, and the like. It adopts the MVC architecture, allowing for clean separation of concerns.

Yii provides an impressive library of extensions available at http://www.yiiframework.com/extensions. The majority of extensions are distributed as composer packages. They empower us with accelerated development. We can easily package our code as extensions and share it with others. This makes Yii even more interesting for modular application development.

Official documentation is quite comprehensive. There are also several books available.

Rich documentation, a vibrant community, active releases, performance optimization, security emphasis, feature richness, and flexibility make Yii a choice worth evaluating.

Phalcon

Phalcon is released under a BSD License, and can be downloaded from https://phalconphp.com.

Phalcon was originally released in 2012, by Andres Gutierrez and collaborators. The goal of the project was to find a new approach to traditional web application frameworks written in PHP. This new approach came in the form of C language extensions. The entire Phalcon framework is developed as a C extension.

The benefits of C-based frameworks lies in the fact that an entire PHP extension is loaded during runtime. This greatly reduces I/O operations massively since there is no need to load .php files any more. Furthermore, compiled C language code executes faster than PHP bytecode. Since C extensions are loaded together with PHP one time during the web server daemon start process, their memory footprint is small. The downside of C-based frameworks is that the code is compiled, so we cannot easily debug it and patch it as we would with PHP classes.

Low-level architecture and optimizations make Phalcon one of the lowest overheads for MVC-based applications.

Phalcon is a full-stack, loosely coupled framework. While it does provide full MVC structure to our application, it also allows us to use its objects as glue components based on the needs of our application. We can choose if we want to create a full blown MVC application, or the minimal style micro application. Micro applications are suitable to implement small applications, APIs, and prototypes in a practical way.

All of the frameworks we mentioned so far enable some form of extensions, where we can add new libraries or entire packages to a framework. Since Phalcon is a C-code framework, contributions to the framework doesn't come in the form of PHP code. On the other hand, writing and compiling C language code can be somewhat challenging for an average PHP developer.

Zephir project http://zephir-lang.com addresses these challenges by introducing high-level Zephir language. Zephir is designed to ease the creation and maintainability of C extensions for PHP with a focus on type and memory safety.

When communicating with databases, Phalcon uses Phalcon Query Language, PhalconQL, or simply PHQL for short. PHQL is a high-level, object-oriented SQL dialect that allows us to write queries using SQL-like language that works with objects instead of tables.

View templates are handled by Volt, Phalcon's own templating engine. It is highly integrated with other components, and can be used independently in our applications.

Phalcon is pretty easy to pick up. Its documentation covers both the MVC and micro applications style of using a framework, with practical examples. The framework itself is rich enough to support the structure and libraries we need for most of today's applications. On top of that, there is an official Phalcon website called Phalconist https://phalconist.com which provides additional resources to framework.

Though there is no official company behind it, no certifications, no commercial support, and similar enterprise looking things, Phalcon does a great job of positioning itself as a choice worth evaluating even with a robust enterprise application development.

 

Summary


Looking back on the release of PHP 5 and its support to OOP programming, we can see the enormous positive impact it had on the PHP ecosystem. A large number of frameworks and libraries have sprawled out, offering enterprise level solutions to web application development.

The release of PHP 7 is likely to be another leap forward for the PHP ecosystem. Though none of the new features are revolutionary as such, as they can be found in other programming languages from years ago, they impact PHP greatly. We are yet to see how its new features will reshape existing and future frameworks and the way we write applications.

The introduction of more advanced errors to exceptions handling, scalar type hints, and function return type hints will surely bring much awaited stability to applications and frameworks using them. The speed improvements compared to PHP 5.6 are significant enough to cut down the hosting costs for higher load sites. Thankfully, the PHP development team minimized backward incomparability changes, so they should not stand in the way of swift PHP 7 adoption.

Choosing the right framework is all but an easy task. What classifies a framework as an enterprise class framework is more than just collection of classes. It has an entire ecosystem around it.

One should never be driven by hype when evaluating a framework for a project. Questions like the following should be taken into consideration:

  • Is it company or community driven?

  • Does it provide quality documentation?

  • Does it have a stable and frequent release cycle?

  • Does it provide some official form of certification?

  • Does it provide free and commercial support?

  • Does it have occasional seminars we can attend?

  • Is it open towards community involvement, so we can submit functionalities and patches?

  • Is it a full-stack or glue type of framework?

  • Is it convention or configuration driven?

  • Does it provide enough libraries to get you started (security, validation, templating, database abstractions, ORMs, routing, internationalization, and so on)?

  • Can the core framework be extended and overridden enough to make it more future proof with possible changes?

There are a number of established PHP frameworks and libraries out there, so the choice is all but easy. Most of these frameworks and libraries are still to fully catch up with the latest features added in PHP 7.

Moving forward, in the next chapter, we will look into common design patterns and how to integrate them in PHP.

About the Author
  • Branko Ajzele

    Branko Ajzele is a respected and highly accomplished software developer, book author, solution specialist, consultant, and team leader. He currently works for Interactive Web Solutions Ltd (iWeb), where he holds the role of senior developer and is the director of iWeb's Croatia office. Branko holds several respected IT certifications, including Zend Certified PHP Engineer, Magento Certified Developer, Magento Certified Developer Plus, Magento Certified Solution Specialist, Magento 2 Certified Solution Specialist, Magento 2 Certified Professional Developer, to mention just a few. He was crowned the e-commerce Developer of the Year by the Digital Entrepreneur Awards in October 2014 for his excellent knowledge and expertise in e-commerce development.

    Browse publications by this author
Latest Reviews (14 reviews total)
Material com qualidade e a preços bastante acessíveis.
Als ebook een slechte layout, moeilijk te volgen. Inhoudelijk een tegenvaller: onduidelijk en voor mij niet relevant.
Very useful reference on my pad.
Modular Programming with PHP 7
Unlock this book and the full library FREE for 7 days
Start now