Table of Contents for
PHP 7: Real World Application Development

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition PHP 7: Real World Application Development by Branko Ajzele Published by Packt Publishing, 2016
  1. Cover
  2. Table of Contents
  3. PHP 7: Real World Application Development
  4. PHP 7: Real World Application Development
  5. PHP 7: Real World Application Development
  6. Credits
  7. Preface
  8. What you need for this learning path
  9. Who this learning path is for
  10. Reader feedback
  11. Customer support
  12. 1. Module 1
  13. 1. Building a Foundation
  14. PHP 7 installation considerations
  15. Using the built-in PHP web server
  16. Defining a test MySQL database
  17. Installing PHPUnit
  18. Implementing class autoloading
  19. Hoovering a website
  20. Building a deep web scanner
  21. Creating a PHP 5 to PHP 7 code converter
  22. 2. Using PHP 7 High Performance Features
  23. Understanding the abstract syntax tree
  24. Understanding differences in parsing
  25. Understanding differences in foreach() handling
  26. Improving performance using PHP 7 enhancements
  27. Iterating through a massive file
  28. Uploading a spreadsheet into a database
  29. Recursive directory iterator
  30. 3. Working with PHP Functions
  31. Developing functions
  32. Hinting at data types
  33. Using return value data typing
  34. Using iterators
  35. Writing your own iterator using generators
  36. 4. Working with PHP Object-Oriented Programming
  37. Developing classes
  38. Extending classes
  39. Using static properties and methods
  40. Using namespaces
  41. Defining visibility
  42. Using interfaces
  43. Using traits
  44. Implementing anonymous classes
  45. 5. Interacting with a Database
  46. Using PDO to connect to a database
  47. Building an OOP SQL query builder
  48. Handling pagination
  49. Defining entities to match database tables
  50. Tying entity classes to RDBMS queries
  51. Embedding secondary lookups into query results
  52. Implementing jQuery DataTables PHP lookups
  53. 6. Building Scalable Websites
  54. Creating a generic form element generator
  55. Creating an HTML radio element generator
  56. Creating an HTML select element generator
  57. Implementing a form factory
  58. Chaining $_POST filters
  59. Chaining $_POST validators
  60. Tying validation to a form
  61. 7. Accessing Web Services
  62. Converting between PHP and XML
  63. Creating a simple REST client
  64. Creating a simple REST server
  65. Creating a simple SOAP client
  66. Creating a simple SOAP server
  67. 8. Working with Date/Time and International Aspects
  68. Using emoticons or emoji in a view script
  69. Converting complex characters
  70. Getting the locale from browser data
  71. Formatting numbers by locale
  72. Handling currency by locale
  73. Formatting date/time by locale
  74. Creating an HTML international calendar generator
  75. Building a recurring events generator
  76. Handling translation without gettext
  77. 9. Developing Middleware
  78. Authenticating with middleware
  79. Using middleware to implement access control
  80. Improving performance using the cache
  81. Implementing routing
  82. Making inter-framework system calls
  83. Using middleware to cross languages
  84. 10. Looking at Advanced Algorithms
  85. Using getters and setters
  86. Implementing a linked list
  87. Building a bubble sort
  88. Implementing a stack
  89. Building a binary search class
  90. Implementing a search engine
  91. Displaying a multi-dimensional array and accumulating totals
  92. 11. Implementing Software Design Patterns
  93. Creating an array to object hydrator
  94. Building an object to array hydrator
  95. Implementing a strategy pattern
  96. Defining a mapper
  97. Implementing object-relational mapping
  98. Implementing the Pub/Sub design pattern
  99. 12. Improving Web Security
  100. Filtering $_POST data
  101. Validating $_POST data
  102. Safeguarding the PHP session
  103. Securing forms with a token
  104. Building a secure password generator
  105. Safeguarding forms with a CAPTCHA
  106. Encrypting/decrypting without mcrypt
  107. 13. Best Practices, Testing, and Debugging
  108. Using Traits and Interfaces
  109. Universal exception handler
  110. Universal error handler
  111. Writing a simple test
  112. Writing a test suite
  113. Generating fake test data
  114. Customizing sessions using session_start parameters
  115. A. Defining PSR-7 Classes
  116. Implementing PSR-7 value object classes
  117. Developing a PSR-7 Request class
  118. Defining a PSR-7 Response class
  119. 2. Module 2
  120. 1. Setting Up the Environment
  121. Setting up Debian or Ubuntu
  122. Setting up CentOS
  123. Setting up Vagrant
  124. Summary
  125. 2. New Features in PHP 7
  126. New operators
  127. Uniform variable syntax
  128. Miscellaneous features and changes
  129. Summary
  130. 3. Improving PHP 7 Application Performance
  131. HTTP server optimization
  132. HTTP persistent connection
  133. Content Delivery Network (CDN)
  134. CSS and JavaScript optimization
  135. Full page caching
  136. Varnish
  137. The infrastructure
  138. Summary
  139. 4. Improving Database Performance
  140. Storage engines
  141. The Percona Server - a fork of MySQL
  142. MySQL performance monitoring tools
  143. Percona XtraDB Cluster (PXC)
  144. Redis – the key-value cache store
  145. Memcached key-value cache store
  146. Summary
  147. 5. Debugging and Profiling
  148. Profiling with Xdebug
  149. PHP DebugBar
  150. Summary
  151. 6. Stress/Load Testing PHP Applications
  152. ApacheBench (ab)
  153. Siege
  154. Load testing real-world applications
  155. Summary
  156. 7. Best Practices in PHP Programming
  157. Test-driven development (TDD)
  158. Design patterns
  159. Service-oriented architecture (SOA)
  160. Being object-oriented and reusable always
  161. PHP frameworks
  162. Version control system (VCS) and Git
  163. Deployment and Continuous Integration (CI)
  164. Summary
  165. A. Tools to Make Life Easy
  166. Git – A version control system
  167. Grunt watch
  168. Summary
  169. B. MVC and Frameworks
  170. Laravel
  171. Lumen
  172. Apigility
  173. Summary
  174. 3. Module 3
  175. 1. Ecosystem Overview
  176. Summary
  177. 2. GoF Design Patterns
  178. Structural patterns
  179. Behavioral patterns
  180. Summary
  181. 3. SOLID Design Principles
  182. Open/closed principle
  183. Liskov substitution principle
  184. Interface Segregation Principle
  185. Dependency inversion principle
  186. Summary
  187. 4. Requirement Specification for a Modular Web Shop App
  188. Wireframing
  189. Defining a technology stack
  190. Summary
  191. 5. Symfony at a Glance
  192. Creating a blank project
  193. Using Symfony console
  194. Controller
  195. Routing
  196. Templates
  197. Forms
  198. Configuring Symfony
  199. The bundle system
  200. Databases and Doctrine
  201. Testing
  202. Validation
  203. Summary
  204. 6. Building the Core Module
  205. Dependencies
  206. Implementation
  207. Unit testing
  208. Functional testing
  209. Summary
  210. 7. Building the Catalog Module
  211. Dependencies
  212. Implementation
  213. Unit testing
  214. Functional testing
  215. Summary
  216. 8. Building the Customer Module
  217. Dependencies
  218. Implementation
  219. Unit testing
  220. Functional testing
  221. Summary
  222. 9. Building the Payment Module
  223. Dependencies
  224. Implementation
  225. Unit testing
  226. Functional testing
  227. Summary
  228. 10. Building the Shipment Module
  229. Dependencies
  230. Implementation
  231. Unit testing
  232. Functional testing
  233. Summary
  234. 11. Building the Sales Module
  235. Dependencies
  236. Implementation
  237. Unit testing
  238. Functional testing
  239. Summary
  240. 12. Integrating and Distributing Modules
  241. Understanding GitHub
  242. Understanding Composer
  243. Understanding Packagist
  244. Summary
  245. Bibliography
  246. Index

Chapter 2. New Features in PHP 7

PHP 7 has introduced new features that can help programmers write high-performing and effective code. Also, some old-fashioned features are completely removed, and PHP 7 will throw an error if used. Most of the fatal errors are now exceptions, so PHP won't show an ugly fatal error message any more; instead, it will go through an exception with the available details.

In this chapter, we will cover the following topics:

  • Type hints
  • Namespaces and group use declarations
  • The anonymous classes
  • Old-style constructor deprecation
  • The Spaceship operator
  • The null coalesce operator
  • Uniform variable syntax
  • Miscellaneous changes

OOP features

PHP 7 introduced a few new OOP features that will enable developers to write clean and effective code. In this section, we will discuss these features.

Type hints

Prior to PHP 7, there was no need to declare the data type of the arguments passed to a function or class method. Also, there was no need to mention the return data type. Any data type can be passed to and returned from a function or method. This is one of the huge problems in PHP, in which it is not always clear which data types should be passed or received from a function or method. To fix this problem, PHP 7 introduced type hints. As of now, two type hints are introduced: scalar and return type hints. These are discussed in the following sections.

Type hints is a feature in both OOP and procedural PHP because it can be used for both procedural functions and object methods.

Scalar type hints

PHP 7 made it possible to use scalar type hints for integers, floats, strings, and Booleans for both functions and methods. Let's have a look at the following example:

class Person
{
  public function age(int $age)
  {
    return $age;
    }

  public function name(string $name)
  {
    return $name;
    }

  public function isAlive(bool $alive)
  {
    return $alive;
    }

}

$person = new Person();
echo $person->name('Altaf Hussain');
echo $person->age(30);
echo $person->isAlive(TRUE);

In the preceding code, we created a Person class. We have three methods, and each method receives different arguments whose data types are defined with them, as is highlighted in the preceding code. If you run the preceding code, it will work fine as we will pass the desired data types for each method.

Age can be a float, such as 30.5 years; so, if we pass a float number to the age method, it will still work, as follows:

echo $person->age(30.5);

Why is that? It is because, by default, scalar type hints are nonrestrictive. This means that we can pass float numbers to a method that expects an integer number.

To make it more restrictive, the following single-line code can be placed at the top of the file:

declare(strict_types = 1);

Now, if we pass a float number to the age function, we will get an Uncaught Type Error, which is a fatal error that tells us that Person::age must be of the int type given the float. Similar errors will be generated if we pass a string to a method that is not of the string type. Consider the following example:

echo $person->isAlive('true');

The preceding code will generate the fatal error as the string is passed to it.

Return type hints

Another important feature of PHP 7 is the ability to define the return data type for a function or method. It behaves the same way scalar type hints behave. Let's modify our Person class a little to understand return type hints, as follows:

class Person
{
  public function age(float $age) : string
  {
    return 'Age is '.$age;
  }

  public function name(string $name) : string
  {
    return $name;
    }

  public function isAlive(bool $alive) : string
  {
    return ($alive) ? 'Yes' : 'No';
  }

}

The changes in the class are highlighted. The return type is defined using the: data-type syntax. It does not matter if the return type is the same as the scalar type. These can be different as long as they match their respective data types.

Now, let's try an example with the object return type. Consider the previous Person class and add a getAddress method to it. Also, we will add a new class, Address, to the same file, as shown in the following code:

class Address 
{
  public function getAddress()
  {
  return ['street' => 'Street 1', 'country' => 'Pak'];
  }
}

class Person
{
  public function age(float $age) : string
  {
    return 'Age is '.$age;
  }

  public function name(string $name) : string
  {
    return $name;
  }

  public function isAlive(bool $alive) : string
  {
    return ($alive) ? 'Yes' : 'No';
  }

  public function getAddress() : Address
  {
  return new Address();
  }
}

The additional code added to the Person class and the new Address class is highlighted. Now, if we call the getAddress method of the Person class, it will work perfectly and won't throw an error. However, let's suppose that we change the return statement, as follows:

public function getAddress() : Address
{
  return ['street' => 'Street 1', 'country' => 'Pak'];
}

In this case, the preceding method will throw an uncaught exception similar to the following:

Fatal error: Uncaught TypeError: Return value of Person::getAddress() must be an instance of Address, array returned

This is because we return an array instead of an Address object. Now, the question is: why use type hints? The big advantage of using type hints is that it will always avoid accidentally passing or returning wrong and unexpected data to methods or functions.

As can be seen in the preceding examples, this makes the code clear, and by looking at the declarations of the methods, one can exactly know which data types should be passed to each of the methods and what kind of data is returned by looking into the code of each method or comment, if any.

Namespaces and group use declaration

In a very large codebase, classes are divided into namespaces, which makes them easy to manage and work with. However, if there are too many classes in a namespace and we need to use 10 of them, then we have to type the complete use statement for all these classes.

Note

In PHP, it is not required to divide classes in subfolders according to their namespace, as is the case with other programming languages. Namespaces just provide a logical separation of classes. However, we are not limited to placing our classes in subfolders according to our namespaces.

For example, we have a Publishers/Packt namespace and the classes Book, Ebook, Video, and Presentation. Also, we have a functions.php file, which has our normal functions and is in the same Publishers/Packt namespace. Another file, constants.php, has the constant values required for the application and is in the same namespace. The code for each class and the functions.php and constants.php files is as follows:

//book.php
namespace Publishers\Packt;

class Book 
{
  public function get() : string
  {
    return get_class();
  }
}

Now, the code for the Ebook class is as follows:

//ebook.php
namespace Publishers\Packt;

class Ebook 
{
  public function get() : string
  {
    return get_class();
  }
}

The code for the Video class is as follows:

//presentation.php
namespace Publishers\Packt;

class Video 
{
  public function get() : string
  {
    return get_class();
  }
}

Similarly, the code for the presentation class is as follows:

//presentation.php
namespace Publishers\Packt;

class Presentation 
{
  public function get() : string
  {
    return get_class();
  }
}

All the four classes have the same methods, which return the classes' names using the PHP built-in get_class() function.

Now, add the following two functions to the functions.php file:

//functions.php

namespace Publishers\Packt;

function getBook() : string
{
  return 'PHP 7';
}
function saveBook(string $book) : string
{
  return $book.' is saved';
}

Now, let's add the following code to the constants.php file:

//constants.php
  
namespace Publishers/Packt;

const COUNT = 10;
const KEY = '123DGHtiop09847';
const URL = 'https://www.Packtpub.com/';

The code in both functions.php and constants.php is self-explanatory. Note that each file has a namespace Publishers/Packt line at the top, which makes these classes, functions, and constants belong to this namespace.

Now, there are three ways to use the classes, functions, and constants. Let's consider each one.

Take a look at the following code:

//Instantiate objects for each class in namespace

$book = new Publishers\Packt\Book();
$ebook = new Publishers\Packt\Ebook();
$video = new Publishers\Packt\Video();
$presentation = new Publishers\Packt\Presentation();

//Use functions in namespace

echo Publishers/Packt/getBook();
echo Publishers/Packt/saveBook('PHP 7 High Performance');

//Use constants

echo Publishers\Packt\COUNT;
echo Publishers\Packt\KEY;

In the preceding code, we used namespace names directly while creating objects or using functions and constants. The code looks fine, but it is cluttered. Namespace is everywhere, and if we have lots of namespaces, it will look very ugly, and the readability will be affected.

Note

We did not include class files in the previous code. Either the include statements or PHP's __autoload function can be used to include all the files.

Now, let's rewrite the preceding code to make it more readable, as follows:

use Publishers\Packt\Book;
use Publishers\Packt\Ebook;
use Publishers\Packt\Video;
use Publishers\Packt\Presentation;
use function Publishers\Packt\getBook;
use function Publishers\Packt\saveBook;
use const Publishers\Packt\COUNT;
use const Publishers\Packt\KEY;

$book = new Book();
$ebook = new Ebook(();
$video = new Video();
$pres = new Presentation();

echo getBook();
echo saveBook('PHP 7 High Performance');

echo COUNT; 
echo KEY;

In the preceding code, at the top, we used PHP statements for specific classes, functions, and constants in a namespace. However, we still wrote duplicate lines of code for each class, function, and/or constant. This may lead to us have lots of use statements at the top of the file, and the overall verbosity would not be good.

To fix this problem, PHP 7 introduced group use declaration. There are three types of group use declarations:

  • Non mixed use declarations
  • Mixed use declarations
  • Compound use declarations

Non mixed group use declarations

Consider that we have different types of features in a namespace, as we have classes, functions, and contacts in a namespace. In non mixed group use declarations, we declare them separately using a use statement. To better understand it, take a look at the following code:

use Publishers\Packt\{ Book, Ebook, Video, Presentation };
use function Publishers\Packt\{ getBook, saveBook };
use const Publishers\Packt\{ COUNT, KEY };

We have three types of features in a namespace: class, functions, and constants. So, we have used separate group use declaration statements to use them. The code is now looking more cleaner, organized, and readable and doesn't require too much duplicate typing.

Mixed group use declarations

In this declaration, we combine all types into a single use statement. Take a look at the following code:

use Publishers\Packt\{ 
  Book,
  Ebook,
  Video,
  Presentation,
  function getBook,
  function saveBook,
  const COUNT,
  const KEY
};

The compound namespace declaration

To understand the compound namespace declaration, we will consider the following criteria.

Let's say we have a Book class in the Publishers\Packt\Paper namespace. Also, we have an Ebook class in the Publishers\Packt\Electronic namespace. The Video and Presentation classes are in the Publishers\Packt\Media namespace. So, to use these classes, we will use the code, as follows:

use Publishers\Packt\Paper\Book;
use Publishers\Packt\Electronic\Ebook;
use Publishers\Packt\Media\{Video,Presentation};

In the compound namespace declaration, we can use the preceding namespaces as follows:

use Publishers\Packt\{
  Paper\Book,
  Electronic\Ebook,
  Media\Video,
  Media\Presentation
};

It is more elegant and clear, and it doesn't require extra typing if the namespace names are long.

The anonymous classes

An anonymous class is a class that is declared and instantiated at the same time. It does not have a name and can have the full features of a normal class. These classes are useful when a single one-time small task is required to be performed and there is no need to write a full-blown class for it.

Note

While creating an anonymous class, it is not named, but it is named internally in PHP with a unique reference based on its address in the memory block. For example, the internal name of an anonymous class may be class@0x4f6a8d124.

The syntax of this class is the same as that of the named classes, but only the name of the class is missing, as shown in the following syntax:

new class(argument) { definition };

Let's look at a basic and very simple example of an anonymous class, as follows:

$name = new class() {
  public function __construct()
  {
    echo 'Altaf Hussain';
  }
};

The preceding code will just display the output as Altaf Hussain.

Arguments can also be passed to the anonymous class constructor, as shown in the following code:

$name = new class('Altaf Hussain') {
  public function __construct(string $name)
  {
    echo $name;
  }
};

This will give us the same output as the first example.

Anonymous classes can extend other classes and have the same parent-child classes functioning as normal named classes. Let's have another example; take a look at the following:

class Packt
{
  protected $number;
  
  public function __construct()
  {
    echo 'I am parent constructor';
  }

  public function getNumber() : float
  {
    return $this->number;
  }
}

$number = new class(5) extends packt
{
  public function __construct(float $number)
  {
    parent::__construct();
    $this->number = $number;
  }
};

echo $number->getNumber();

The preceding code will display I am parent constructor and 5. As can be seen, we extended the Packt class the way we extend named classes. Also, we can access the public and protected properties and methods within the anonymous class and public properties and methods using anonymous class objects.

Anonymous classes can implement interfaces too, the same as named classes. Let's create an interface first. Run the following:

interface Publishers
{
  public function __construct(string $name, string $address);
  public function getName();
  public function getAddress();
}

Now, let's modify our Packt class as follows. We added the highlighted code:

class Packt
{
  protected $number;
  protected $name;
  protected $address;
  public function …
}

The rest of the code is same as the first Packt class. Now, let's create our anonymous class, which will implement the Publishers interface created in the previous code and extend the new Packt class, as follows:

$info = new class('Altaf Hussain', 'Islamabad, Pakistan')extends packt implements Publishers
{
  public function __construct(string $name, string $address)
  {
    $this->name = $name;
    $this->address = $address;
  }

  public function getName() : string
  {
  return $this->name;
  }

  public function getAddress() : string
  {
  return $this->address;
  }
}

echo $info->getName(). ' '.$info->getAddress();

The preceding code is self-explanatory and will output Altaf Hussain along with the address.

It is possible to use anonymous classes within another class, as shown here:

class Math
{
  public $first_number = 10;
  public $second_number = 20;

  public function add() : float
  {
    return $this->first_number + $this->second_number;
  }

  public function multiply_sum()
  {
    return new class() extends Math
    {
      public function multiply(float $third_number) : float
      {
        return $this->add() * $third_number;
      }
    };
  }
}

$math = new Math();
echo $math->multiply_sum()->multiply(2);

The preceding code will return 60. How does this happen? The Math class has a multiply_sum method that returns the object of an anonymous class. This anonymous class is extended from the Math class and has a multiply method. So, our echo statement can be divided into two parts: the first is $math->multiply_sum(), which returns the object of the anonymous class, and the second is ->multiply(2), in which we chained this object to call the anonymous class's multiply method along with an argument of the value 2.

In the preceding case, the Math class can be called the outer class, and the anonymous class can be called the inner class. However, remember that it is not required for the inner class to extend the outer class. In the preceding example, we extended it just to ensure that the inner classes could have access to the outer classes' properties and methods by extending the outer classes.

Old-style constructor deprecation

Back in PHP 4, the constructor of a class has the same name method as that of the class. It is still used and is valid until PHP's 5.6 version. However, now, in PHP 7, it is deprecated. Let's have an example, as shown here:

class Packt
{
  public function packt()
  {
    echo 'I am an old style constructor';
  }
}

$packt = new Packt();

The preceding code will display the output I am an old style constructor with a deprecated message, as follows:

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Packt has a deprecated constructor in…

However, the old style constructor is still called. Now, let's add the PHP __construct method to our class, as follows:

class Packt
{
  public function __construct()
  {
    echo 'I am default constructor';
  }

  public function packt()
  {
    echo 'I am just a normal class method';
  }
}

$packt = new Packt();
$packt->packt();

In the preceding code, when we instantiated the object of the class, the normal __construct constructor was called. The packt()method isn't considered a normal class method.

Note

Old-style constructors are deprecated, which means that they will still work in PHP 7 and a deprecated message will be displayed, but it will be removed in the upcoming versions. It is best practice to not use them.

The throwable interface

PHP 7 introduced a base interface that can be base for every object that can use the throw statement. In PHP, exceptions and errors can occur. Previously, exceptions could be handled, but it was not possible to handle errors, and thus, any fatal error caused the complete application or a part of the application to halt. To make errors (the most fatal errors) catchable as well, PHP 7 introduced the throwable interface, which is implemented by both the exception and error.

Note

The PHP classes we created can't implement the throwable interface. If required, these classes must extend an exception.

We all know exceptions, so in this topic, we will only discuss errors, which can handle the ugly, fatal errors.

Error

Almost all fatal errors can now throw an error instance, and similarly to exceptions, error instances can be caught using the try/catch block. Let's have a simple example:

function iHaveError($object)
{
  return $object->iDontExist();
  {

//Call the function
iHaveError(null);
echo "I am still running";

If the preceding code is executed, a fatal error will be displayed, the application will be halted, and the echo statement won't be executed in the end.

Now, let's place the function call in the try/catch block, as follows:

try 
{
  iHaveError(null);
} catch(Error $e)
{
  //Either display the error message or log the error message
  echo $e->getMessage();
}

echo 'I am still running';

Now, if the preceding code is executed, the catch body will be executed, and after this, the rest of the application will continue running. In the preceding case, the echo statement will be executed.

In most cases, the error instance will be thrown for the most fatal errors, but for some errors, a subinstance of error will be thrown, such as TypeError, DivisionByZeroError, ParseError, and so on.

Now, let's take a look at a DivisionByZeroError exception in the following example:

try
{
  $a = 20;
  $division = $a / 20;
} catch(DivisionByZeroError $e) 
{
  echo $e->getMessage();
}

Before PHP 7, the preceding code would have issued a warning about the division by zero. However, now in PHP 7, it will throw a DivisionByZeroError, which can be handled.