Modern PHP

First and foremost, I recommend this book; it is not voluminous, and one can immerse oneself and complete it in half a day. The initial section primarily introduces new features, while the latter delves into tools and procedures for testing and deployment. It does not delve into coding techniques but rather expounds on the modernized engineering development, testing, and deployment practices within the realm of PHP. Indeed, this is of paramount importance; PHP necessitates an elegant and effective means of standardizing engineering development.

This book is based on PHP version 5.6; after all, PHP 7 had not been released at that time. However, readers should approach this book with a contemporary perspective, as technology continually advances. From the author’s initial compilation to the publication and even translation, a significant amount of time has elapsed.

From another perspective, the internet is the swiftest means of acquiring knowledge, and proficiency in English is crucial.

While organizing my notes, I will incorporate some PHP7 (up to 7.1) features and aspects not covered in the book but which I have encountered more frequently, indicated as “supplement.”

Language Innovations

Namespace (5.3)

This serves as the foundation of the modern PHP component ecosystem.

Official Documentation

A namespace is akin to a directory in an operating system; two identically named files can coexist in different directories. Likewise, two identically named PHP classes can coexist under different PHP namespaces. It is as straightforward as that.

Your code is highly likely to share class names, interface names, function names, or constant names with other developers’ code. Without the use of namespaces, conflicts may arise, leading to PHP execution errors. However, by employing namespaces and placing your code within a unique vendor namespace, you can utilize identical names to designate classes, interfaces, functions, and constants.

Some code may lack namespaces and exist in the global namespace. When referencing global namespace code within a namespace, you need to prefix it with a backslash, such as when calling PHP’s native Exception class from within your own namespace.

Late Static Binding (Supplement 5.3)

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        self::who();
    }
}
class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}
B::test();
// Output: A
<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Late static binding begins here
    }
}
class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}
B::test();
// Output: B

“Late binding” means that static:: is no longer resolved as the class in which the method was defined but is instead determined at runtime. It can also be referred to as “late static binding” because it can be used for (but is not limited to) calling static methods.

Using Interfaces

Interfaces are not features per se but represent a crucial concept within object-oriented programming.

An interface serves as a contract between two PHP objects, with the goal not being to establish a dependency on another object’s identity but rather to rely on its capabilities.

Using Traits (5.4)

Traits specify what a trait can do, providing a modular implementation resembling both classes and interfaces. However, they are neither, as traits comprise partial class implementations, including constants, properties, and methods, which can be mixed into one or more PHP classes.

Official Documentation

Consider this: both phones and cars have location functionality. They are unrelated and should not inherit from the same parent class. However, how can they reuse location-related functionality? In contemporary projects, we achieve this by encapsulating it in a service.

In Laravel, you’ll often encounter the use of traits, as seen in the authentication service:

class LoginController extends Controller
{
    use AuthenticatesUsers;
    //...
}
trait AuthenticatesUsers
{
    //...
}

Traits are designed for code reuse in single-inheritance languages like PHP. They address typical issues related to multiple inheritance and mixin classes.

Generators (5.5)

Generators are iterators that only advance forward, meaning you cannot use generators for operations like moving backward, skipping, or searching within a data set. They solely allow generators to compute and produce the next value.

<?php
  function makeRange($length)
{
  for($i = 0;$i < $length;$i++){
    yield $i;
  }  
}
foreach(makeRange(10000000) as $i){
  echo $i.PHP_EOL;
}

Each time a value is generated, it is returned as a result of the yield keyword, and the function execution pauses. When the next method of the returned iterator is called, execution resumes from where it was last paused by the yield keyword. foreach automatically invokes the next method.

There are more advanced uses, detailed in the Bird Brother’s blog.

In PHP7, after a generator has iterated through all its values, you can obtain the generator function’s return value (if it contains a return statement) using Generator::getReturn().

Closures | Anonymous Functions (5.3)

Closures in PHP are fascinating. They can reference external variables and potentially retain their state until they are used.

The most common use of closures is in functions like array_map:

<?php
  $result = array_map(function($value){
    return $value + 1;
  },[1,2,3]);
  print_r($result);
  //[2,3,4];

Or you can create a closure directly. In terms of implementation, it involves the _invoke() method; refer to the official documentation for more details:

<?php
  $closure = function($blogName){
  return 'Welcome to '.$blogName;
}
echo $closure('chengxiaobai');
//Welcome to chengxiaobai

Appending an external state to a closure:

<?php
  function hello($blogName){
    return function($userName) use ($blogName){
      return sprintf('Hello %s, welcome to %s',$userName,$blogName);
    }
  }
//Attach 'chengxiaobai' to the closure
$helloString = hello('chengxiaobai');
//Call the closure normally
echo $helloString('Tom');
//Hello Tom, welcome to chengxiaobai;

//Alternatively, achieve the same effect as follows:
$blogName = 'chengxiaobai';
$helloString = function($userName) use ($blogName){
      return sprintf('Hello %s, welcome to %s',$userName,$blogName);
    };
echo $helloString('Tom');
//Hello Tom, welcome to chengxiaobai;

There’s also an intriguing bindTo method

, used in Laravel’s route closures. You might want to explore that in Laravel.

Variable-Length Function Arguments (Supplement 5.6)

<?php
function sum(...$numbers) {
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}
echo sum(1, 2, 3, 4);
// Output: 10

Community (PHP-FIG) Standards (PSR)

For the latest official documentation, refer here

Chinese translation documentation available here (outdated) - for reference only.

The PHP Framework Interoperability Group (PHP-FIG) aims to achieve interoperability among components. This interoperability is achieved through interfaces, autoloading, and standardized coding styles, enabling components to work together seamlessly.

PSR stands for PHP Standards Recommendation, known as PHP recommendations. Each specification addresses specific common issues encountered in PHP frameworks.

It is adherence to these standards that makes it possible to easily use third-party components, reduce duplicated efforts, and improve overall coding quality within the community. Symfony, for instance, is a prime example.

Number Description Note
1 Basic Coding Standard
2 Coding Style Guide
3 Logger Interface
4 Autoloading Standard
6 Caching Interface
7 HTTP Message Interface
13 Hypermedia Links
16 Simple Cache

Formerly, there was PSR-0, which was an autoloading standard, but it has been replaced by PSR-4. However, some frameworks still use PSR-0; for instance, Bird Brother’s Yaf framework.

Components

Before the concept of components gained popularity, developers would choose a full-stack framework to build applications and solve problems. They would invest significant time learning the enclosed ecosystem of that framework and utilize the tools it provided. However, integrating third-party libraries or custom libraries into such frameworks could be challenging because they often did not follow the same interface.

So, what are components? Components are pre-packaged code designed to solve a specific problem. Examples include Guzzle and Monolog.

When selecting a suitable component, several factors should be considered:

  • Single Responsibility: The component should focus on solving a single problem effectively, avoiding the temptation to be a one-size-fits-all solution.
  • Conciseness
  • Adaptability: It should integrate seamlessly with existing code and work well with other components. Avoid components with invasive behaviors that might alter, for instance, default time zones.
  • Testability: Components should have comprehensive test cases and clear documentation on how to use them, helping increase test coverage.
  • Thorough Documentation: Components should have comprehensive documentation to facilitate understanding and usage.
  • Community Activity.

You can find many components on Packagist, a repository specifically for collecting PHP components. To make the most of this resource, it’s essential to use Composer, although PEAR is still available, I recommend leaning towards Composer.

When it comes to choosing between components and frameworks, remember to use the right tool for the job. Components and frameworks each have their role. Most modern frameworks are built on top of small PHP components that adhere to specific conventions.

In team collaborations, it’s often best to use a framework, not because of the abundance of features it provides, but because of the conventions and agreements it enforces.