BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles PHP 7 — Getting Started and OOP Improvements

PHP 7 — Getting Started and OOP Improvements

Leia em Português

Key Takeaways

  • PHP 7 was the much awaited PHP.next after PHP 5. PHP 7.4 is the final minor version release of PHP 7. 
  • In addition to providing several new features, PHP 7.x is faster and cloud-ready.
  • PHP 7.2 added partial support for Contravariance and Covariance, and PHP 7.4 added full support for the same.  
  • PHP 7.2 added a new type called object
  • PHP continues to be one of the most commonly used languages on the web. PHP is used by 78.6% of websites whose server-side programming language is known.

PHP 7.x brings several improvements and new features that touch all aspects of the language, including better support for object oriented programming, extensions to classes and interfaces, improvements to the type system, error handling, and more. In this series of articles, we discuss new features across the various PHP 7.x versions.

 

PHP had become almost a forgotten language with a lapse of more than 10 years without a new major version after PHP 5.0 in 2004. To make things worse, PHP 6.x was abandoned because of a planned addition of  native Unicode support to PHP that could not be implemented. 

PHP 7.0 is a major version with several improvements and new features added. Some of the salient new features in 7.0 are scalar type declarations for strings, integers, floating-point numbers and booleans; return type declarations; a new function called define() for array constants; and anonymous classes. Some features have been added to improve unicode support including the IntlChar class and the unicode codepoint escape syntax.

Additionally, expectations have been added to enhance the assert() function, while generator return functions and generator delegation improve generator functionality. Subsequent minor versions, including PHP 7.1 through PHP 7.4, added other new features.

In this series of articles, we shall discuss new features in the various PHP 7.x versions. But first, let’s discuss why PHP 7.

Why use PHP 7?

In short, PHP 7 brings PHP to the level of other modern languages.

Some of the  salient reasons to use PHP 7 are as follows:

1. WordPress is used by 36.4% of all websites. PHP 7 is the official recommended PHP version for WordPress

"When updating to a new version of PHP, WordPress encourages updating to its recommended version, PHP 7.3. The PHP internals team has done a great job making its most recent version the fastest version of PHP yet. This means that updating will improve the speed of your site, both for you and your visitors."

2. PHP 7 offers several new features as mentioned before. 

3. PHP 7 is based on a new Zend Engine with better performance and speed. Zend is very fast, as found in several speed benchmark tests run with different platforms/configurations.

4. PHP 7 uses efficient data structures making it leaner compared to earlier versions.

5. PHP 7 is Cloud-ready with most major cloud service providers supporting it in their LAMP Stack.

Setting the Environment

To be able to test or run the sample scripts presented here, download and install the latest PHP 7 version (PHP 7.4). The binaries to download and the steps to install them vary with the platform used, so refer to the official PHP docs for guidance. Do not forget to add the install root directory, e.g., C:\PHP7.4\php-7.4-ts-windows-vc15-x64-r6c9821a, to your PATH environment. Rename php.ini-production or php.ini-development to php.ini.  To use the extensions in the /ext directory set the extension_dir directive in php.ini:

 extension_dir = "./ext"

Start the built-in server with the following command:

php -S localhost:8000

Add all scripts to be run in the scripts sub-directory of the root directory, which is the install directory, e.g.,  C:\PHP7\php-7.3.0-Win32-VC15-x64. The root directory may be set to a different value using the doc_root directive in php.ini. To make the PHP scripts used as examples reusable, save them separately rather than testing/running every script as test.php

Covariance and Contravariance

PHP 7.2 introduced limited covariance and contravariance. Covariance refers to a subclass’s method to be able to return a more specific return type. Contravariance refers to a subclass’s method to accept a less specific parameter type. More/less specific is defined in the context of super/subclass, with a subclass being more specific.  A class extending another class may override its methods while still maintaining contravariance (for parameter types) and covariance (for return type).

Support for covariance and contravariance is limited in PHP 7.2, which implies that only variance to no type is supported. To elaborate,  a return type may be defined in an overriding function where none existed in the super class, and a parameter type may be omitted when overriding a function where a parameter existed in the super class. 

As an example, create a script and declare a class A with a single function, fn1. Create another class B that extends class A and overrides its fn1 function.

The parameter type in the overridden function fn1 is omitted, which defaults to mixed, a parameter type widening from type B in class A.  The provision to omit parameter type/s in overridden methods, whether class is abstract or not,  is another new feature in PHP 7.

The return type in the overridden function fn1 is A, which is a narrowing from the mixed type in class A. The script is listed here:

<?php
class A {
  function fn1(B $b) {} 
}
class B extends A {
  function fn1($b): A{} 
}

New object type

PHP 7.2 has added support for a new type called object  that may be used as a parameter type and return type.  Instances of all class types are objects. To demonstrate using an object as a parameter type and return type, create a script object.php in a directory called scripts in the document root and declare two classes, ClassA and classB, with each class defining a hello() function that echoes a string message.  Next, add a hello() function to the script itself with both parameter type and return type as object. The hello() function added directly in the script returns an instance of class ClassB:

function hello(object $obj) : object
{
	return new ClassB();
}

Invoke the function with an instance of ClassA as argument and invoke the hello() function on the object returned.

hello(new ClassA())->hello();
The object.php is listed:
<?php
Class ClassA{
function hello()
{
	echo "Hello from ClassA";
}}
class ClassB{
function hello()
{
 	echo "Hello from ClassB";
}}
 
function hello(object $obj) : object
{
	return new ClassB();
}
hello(new ClassA())->hello();
?>

Running the script with url http://localhost:8000/scripts/object.php will output:

Hello from ClassB

As this is the first example script we have run, the output in the browser is shown in Figure 1.

Figure 1. Output from object.php

The object type itself does not represent a class; it is just a type.  A new instance of the built-in class stdClass is created if any  type other than object is converted to object.

An array can be converted to an object by casting it to the object type, with the resulting object having properties named  like the array keys. To demonstrate how to convert an array to an object, and several useful related tasks, create an object_array.php script and declare an object by casting it to object.

$obj = (object) array('journal' => 'Oracle Magazine', 'publisher' => 'Oracle Publishing','edition' => 'January February 2018');

Now, you can output the object properties using the named keys.

echo $obj->{'journal'};
echo $obj->{'publisher'};
echo $obj->{'edition'};

The bool isset mixed $var [, mixed $... ] ) function may  be used to find if a property is set as follows.

var_dump(isset($obj->{'journal'}));

Output an object key using the mixed key ( array $array ) function.

var_dump(key($obj));

Advance  the  internal array pointer with mixed next ( array &$array ).

next($obj);

Invoke the isset and key functions for the next array element. Repeat the sequence of invoking next,  isset and key functions for the next element.  Object member variables may be accessed to output their values.

echo $obj->journal; 
echo $obj->publisher;
echo $obj->edition; 

Find if the converted object from the array is an instance of stdClass.

if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}

A string may be converted to object by casting it to object.   The value of the converted object is accessed using the member variable scalar. Find if the converted object is an instance of stdClass.

$obj = (object) 'hello';
echo $obj->scalar;
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}

The object_array.php script is listed.

<?php
$obj = (object) array('journal' => 'Oracle Magazine', 'publisher' => 'Oracle Publishing','edition' => 'January February 2018');
echo $obj->{'journal'};
echo "<br/>";
echo $obj->{'publisher'};
echo "<br/>";
echo $obj->{'edition'};
echo "<br/>";
var_dump(isset($obj->{'journal'})); 
echo "<br/>";
var_dump(key($obj));
next($obj);
echo "<br/>";
var_dump(isset($obj->{'publisher'})); 
echo "<br/>";
var_dump(key($obj));
next($obj);
echo "<br/>";
var_dump(isset($obj->{'edition'})); 
echo "<br/>";
var_dump(key($obj));
echo "<br/>";
echo $obj->journal; 
echo "<br/>";
echo $obj->publisher;
echo "<br/>";
echo $obj->edition; 
echo "<br/>";
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
echo "<br/>";
}
$obj = (object) 'hello';
echo $obj->scalar;
echo "<br/>";
if($obj instanceof stdClass){
echo '$obj is instance of built-in class stdClass';
}
?>

Running the script will output :

Oracle Magazine
Oracle Publishing
January February 2018
bool(true)
string(7) "journal"
bool(true)
string(9) "publisher"
bool(true)
string(7) "edition"
Oracle Magazine
Oracle Publishing
January February 2018
$obj is instance of built-in class stdClass
hello
$obj is instance of built-in class stdClass

You can convert not only arrays and strings to objects, but values of any type, including int, float and bool. As an example convert an int to an object, output its scalar value and find if the converted object is an instance of stdClass with the following script:

<?php
$obj = (object) 1;
echo $obj->scalar;
echo "<br/>";
if($obj instanceof stdClass){
echo '$obj is instance of built-in class StdClass';
}?>

The output is as follows:

1

$obj is instance of built-in class stdClass

Instances of classes are objects and not instances of stdClass,  and casting them to object does not make them an instance of stdClass. To demonstrate this, create a script named object_instance_of.php, then declare a class and instantiate it.  The following script will show you how to find out if a class instance is an instance of stdClass; then the script will cast the class instance to object and find out if the cast object is an instance of stdClass. The object_instance_of.php script is listed. 

<?php
Class A{}
$A = new A;
echo '<br/>';
if ($A instanceof stdClass) {
echo '$A is instance of built-in class stdClass'; }
else{
echo '$A is not instance of built-in class stdClass';
}
echo '<br/>';
echo '<br/>';
$AObj = (object)$A;
 if ($AObj instanceof stdClass) {
 echo   '$AObj is instance of built-in class stdClass';
}else{ echo   '$AObj is not instance of built-in class stdClass';
}
echo '<br/>';
 ?>

The output from  the script is as follows:

$A is not instance of built-in class stdClass
$AObj is not instance of built-in class stdClass

An instance of a named class or anonymous class is already an object and casting it to object does not change its type.  An empty array and the NULL value may also be converted to an object. As mentioned, stdClass is the  default PHP object and an instance of stdClass gets created when  scalars, arrays, and NULL  are cast to object. An anonymous class object, an object created from an empty array, an object created from NULL, or a class with no functions or variables are not considered empty and empty() does not return TRUE when applied to any of them. The empty() function returns TRUE only if a variable or object does not exist or is FALSE.

To test all this, create a object_empty.php script and copy the following listing to it

<?php
$obj1 = (object)(new class{}); // Instantiate anonymous class
$obj2 = (object)[]; // Cast empty array to object
class A{}
$A=new A();  // Instance of empty class
var_dump($A);
echo "<br/>";
var_dump($obj1);
echo "<br/>";
var_dump($obj2);
echo "<br/>"; 
echo empty ($obj1);
echo "<br/>";
$obj1=NULL;
$obj3=(object)$obj1;// NULL cast to object
var_dump($obj3); 
echo "<br/>";
echo empty ($A);
echo "<br/>";
echo empty ($obj2);
echo "<br/>";
echo empty ($obj3);
?>

The script creates each kind of anonymous class object: an object created from an empty array,  an object created from NULL, and a class object with no functions or variables. Running the script will generate the following output.

object(A)#3 (0) { } 
object(class@anonymous)#1 (0) { } 
object(stdClass)#2 (0) { };
object(stdClass)#1 (0) { } 

The object type may be used for contravariance (widening) of parameter type and covariance (narrowing) of return type.

<?php
class A{
public function fn(object $obj)  {
}
}
class B extends A{
public function fn($obj) : object {
} 
} 

Full Covariance and Contravariance 

We already discussed PHP 7.2 support for limited covariance,  which enables adding a return type to a method  in an extended class although none was declared in the super-class.  We also discussed support for limited contravariance,   which enables leaving the type of a method parameter unspecified in an extended class.  

PHP 7.4 adds full support for covariance and contravariance.  Full support allows  less specific parameter types and more specific return types, which implies that a parameter type can be substituted with one of its supertypes and a return type may be substituted by a subtype. Recall that support for covariance and contravariance in PHP 7.2 was limited to a no type. In the following script ClassB extends ClassA and ClassD extends ClassC. Function fn1 in ClassD declares a less specific parameter type and  a more specific return type than in ClassC.

<?php
class ClassA {}
class ClassB extends ClassA {}
class ClassC {
    public function fn1(ClassB $b): ClassA {}
}
class ClassD extends ClassC {
    public function fn1(ClassA $a): ClassB {}
}
?>

Some of the characteristics of full variance support are:

  • Full variance is supported only if auto-loading is used
  • Variance for object type is supported
  • Variance for callable type is not supported
  • By-reference parameters are still contravariant and by-reference return type are still covariant
  • Variance verification is made only after the last consecutive type declaration

In the next article in this series, we shall discuss PHP 7.x new features for classes and interfaces. 

About the Author

Deepak Vohra is a Sun Certified Java Programmer and Sun Certified Web Component Developer. Deepak has published Java and Java EE related technical articles in  WebLogic Developer's Journal, XML Journal, ONJava, java.net, IBM developerWorks, Java Developer’s Journal, Oracle Magazine, and devx. Deepak has published five books on Docker and is a Docker Mentor. Deepak has also published several articles on PHP and a book Ruby on Rails for PHP and Java Developers. 

 

PHP 7.x brings several improvements and new features that touch all aspects of the language, including better support for object oriented programming, extensions to classes and interfaces, improvements to the type system, error handling, and more. In this series of articles, we discuss new features across the various PHP 7.x versions.

 

Rate this Article

Adoption
Style

BT