Improving WordPress Code With Modern PHP
Improving WordPress Code With Modern PHP
Improving WordPress Code With Modern PHP
Leonardo Losoviz
2019-02-22T13:00:38+01:00
2019-02-22T12:20:23+00:00
WordPress was born fifteen years ago, and because it has historically preserved backwards compatibility, newer versions of its code couldn’t make full use of the latest capabilities offered by the newer versions of PHP. While the latest version of PHP is 7.3.2, WordPress still offers support up to PHP 5.2.4.
But those days will soon be over! WordPress will be upgrading its minimum PHP version support, bumping up to PHP 5.6 in April 2019, and PHP 7 in December 2019 (if everything goes according to plan). We can then finally start using PHP’s imperative programming capabilities without fear of breaking our clients’ sites. Hurray!
Because WordPress’ fifteen years of functional code have influenced how developers have built with WordPress, our sites, themes and plugins may be littered with less-than-optimal code that can gladly receive an upgrade.
This article is composed of two parts:
Further features have been added to PHP versions 5.3, 5.4, 5.5, 5.6 and 7.0 (notice that there is no PHP 6) and we’ll explore the most relevant ones.
We’ll take a closer look through these features and how they are able to help us build better software.
Let’s start by exploring PHP’s “new” features.
Our new book, in which Alla Kholmatova explores
how to create effective and maintainable design systems to design great digital products. Meet Design Systems, with common traps, gotchas and the lessons Alla has learned over the years.
Table of Contents →
Classes, OOP, SOLID And Design Patterns
Classes and objects were added to PHP 5, so WordPress already makes use of these features, however, not very extensively or comprehensively: The paradigm of coding in WordPress is mostly functional programming (performing computations by calling functions devoid of application state) instead of object-oriented programming (OOP) (performing computations by manipulating objects’ state). Hence I also describe classes and objects and how to use them through OOP.
OOP is ideal for producing modular applications: Classes allow the creation of components, each of which can implement a specific functionality and interact with other components, and can provide customization through its encapsulated properties and inheritance, enabling a high degree of code reusability. As a consequence, the application is cheaper to test and maintain, since individual features can be isolated from the application and dealt with on their own; there is also a boost of productivity since the developer can use already-developed components and avoid reinventing the wheel for each application.
A class has properties and functions, which can be given visibility by usingprivate
(accessible only from within the defining class), protected
(accessible from within the defining class and its ancestor and inheriting classes) and public
(accessible from everywhere). From within a function, we can access the class’ properties by prepending their names with $this->
:
class Person {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function getIntroduction() {
return sprintf(
__('My name is %s'),
$this->name
);
}
}
A class is instantiated into an object through the new
keyword, after which we can access its properties and functions through ->
:
$person = new Person('Pedro');
echo $person->getIntroduction();
// This prints "My name is Pedro"
An inheriting class can override the public
and protected
functions from its ancestor classes, and access the ancestor functions by prepending them with parent::
:
class WorkerPerson extends Person {
protected $occupation;
public function __construct($name, $occupation) {
parent::__construct($name);
$this->occupation = $occupation;
}
public function getIntroduction() {
return sprintf(
__('%s and my occupation is %s'),
parent::getIntroduction(),
$this->occupation
);
}
}
$worker = new WorkerPerson('Pedro', 'web development');
echo $worker->getIntroduction();
// This prints "My name is Pedro and my occupation is web development"
A method can be made abstract
, meaning that it must be implemented by an inheriting class. A class containing an abstract
method must be made abstract
itself, meaning that it cannot instantiated; only the class implementing the abstract method can be instantiated:
abstract class Person {
abstract public function getName();
public function getIntroduction() {
return sprintf(
__('My name is %s'),
$this->getName()
);
}
}
// Person cannot be instantiated
class Manuel extends Person {
public function getName() {
return 'Manuel';
}
}
// Manuel can be instantiated
$manuel = new Manuel();
Classes can also define static
methods and properties, which live under the class itself and not under an instantiation of the class as an object. These are accessed through self::
from within the class, and through the name of the class + ::
from outside it:
class Factory {
protected static $instances = [];
public static function registerInstance($handle, $instance) {
self::$instances[$handle] = $instance;
}
public static function getInstance($handle) {
return self::$instances[$handle];
}
}
$engine = Factory::getInstance('Engine');
To make the most out of OOP, we can use the SOLID principles to establish a sound yet easily customizable foundation for the application, and design patterns to solve specific problems in a tried-and-tested way. Design patterns are standardized and well documented, enabling developers to understand how different components in the application relate to each other, and provide a way to structure the application in an orderly fashion which helps avoid the use of global variables (such as global $wpdb
) that pollute the global environment.
Namespaces
Namespaces were added to PHP 5.3, hence they are currently missing altogether from the WordPress core.
Namespaces allow organizing the codebase structurally to avoid conflicts when different items have the same name — in a fashion similar to operating system directories which allow to have different files with the same name as long as they are stored in different directories. Namespaces do the same encapsulation trick for PHP items (such as classes, traits, and interfaces) avoiding collisions when different items have the same name by placing them on different namespaces.
Namespaces are a must when interacting with third-party libraries since we can’t control how their items will be named, leading to potential collisions when using standard names such as “File”, “Logger” or “Uploader” for our items. Moreover, even within a single project, namespaces prevent class names from becoming extremely long as to avoid clashes with other classes, which could result in names such as “MyProject_Controller_FileUpload”.
Namespaces are defined using the keyword namespace
(placed on the line immediately after the opening
From our sponsors: Improving WordPress Code With Modern PHP