Key Takeaways
- PHP 7.0 added scalar type declarations for strings, integers, floating-point numbers, and booleans
- PHP 7.0 added support for return type declarations
- PHP 7.1 added support for nullable parameter types and return types
void
is a valid return type as of PHP 7.1- PHP 7.1 added a new compound type called iterable
- PHP 7.4 adds support for typed properties, which is types for class properties
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.
We have already explored some of the improvements introduced in PHP 7.x in two articles: PHP 7 — Getting Started and OOP Improvements and PHP 7 — Classes and Interfaces Improvements. To set the background for this article on PHP’s type system, PHP is a weakly typed language, which implies the data type of variables does not need to be declared.
In this article we explore new type-related features available in PHP 7.x.
Scalar Type Declarations
Type declarations are nothing new to PHP. Type declarations are used to annotate function parameters and annotated parameters require an argument to be of the specified type. Support for type declarations for class, interface, and self
was added in PHP 5.0.0, while support for type declarations for array
was added in PHP 5.1.0, and upport for type declarations for callable
was added in 5.4.0.
PHP 7.0 added support for scalar type declarations for types string
(strings), int
(integers), float
(floating-point numbers), and bool
(booleans).
To demonstrate type declarations with an example, create a script (typedeclr.php) in the document root directory and copy the following listing to the script:
<?php
class A {}
class B extends A {}
class C {}
function f(A $a) {
echo get_class($a)."\n";
}
f(new A);
f(new B);
f(new C);
?>
Class B
extends class A
. Class C
does not extend any class and defines a function f()
with a parameter of type A
. Then, the script invokes function passing instances of class A
, B
and C
successively as arguments. Assuming the same setup as in the first article PHP 7 — Getting Started and OOP Improvements, run the script with url http://localhost:8000/typedeclr.php. While calling f()
passing instances of classes A
and B
does not generate an error and outputs the value defined in function, calling f()
with an argument of type C
generates a TypeError:
AB
Uncaught TypeError. Argument 1 passed to f() must be an instance of A, instance of C given
Now, let’s discuss scalar types. Scalar types come in two kinds, coercive (default) and strict. Create a script sumints.php and define a vararg function taking parameters of type int
. Invoke the function with some of the arguments supplied as floating-point numbers and others as string, for example:
echo SumInts(1,'3',0,3.6);
The sumints.php script is listed below, including a commented-out declare
directive that we will discuss later when we cover strict scalar types
<?php
//declare(strict_types=1);
function SumInts(int ...$ints)
{
return array_sum($ints);
}
echo SumInts(1,'3',0,3.6);
?>
If you run the script, it will output the sum of the args converted to integer values. In other words, wrong type arguments get converted (coerced) to the expected type. A value of 9 is output for the sumints.php as shown in Figure 1.
Figure 1. Output from sumints.php
Floating-point numbers are converted to an integer by removing the fractional value. As an example 3.6 becomes 3 and does not get rounded off to 4. String value ‘3’ gets converted to 3.
Strict scalar type declarations work in a completely different way. First off, strict mode is available only for scalar type declarations and not for class, interface, callable, or array type declarations. Go back to the previous script and comment in the declare()
directive to use strict scalar type declarations. Notice that the declare()
directive must appear at the top of the file in which strict mode for scalar type declarations is to be used.
declare(strict_types=1);
Run the script again and you will see a TypeError
is raised. The TypeError
indicates that the arguments must be of type int
.
Uncaught TypeError: Argument 2 passed to SumInts() must be of the type int, string given
Strict mode does not apply to function calls from internal (built-in) functions.
When using coercive mode (the default mode) for scalar type declarations, a null
value argument does not get coerced or converted to the expected type and a TypeError
is thrown instead. To demonstrate this, create a script sumints_null.php in which a function expecting an integer value is supplied a null
arg:
<?php
function SumInts(int ...$ints)
{
return array_sum($ints);
}
echo SumInts(1,'3',0,null);
?>
If you run the script, you will get a TypeError.
Uncaught TypeError: Argument 4 passed to SumInts() must be of the type int, null given
If you want to allow for a null
argument, you must specify a null
default value for the corresponding parameter as in the script listed below:
<?php
function SumInts(int $a=null)
{
return array_sum($a);
}
echo SumInts(null);
?>
With strict mode, argument values must be of the type defined in the function with one exception: integer values may be supplied to a function expecting a float.
To demonstrate this, create a script sum_floats.php in which a variadic function with float type parameters is defined. Invoke the function passing integers for some of its arguments:
<?php
declare(strict_types=1);
function SumFloats(float ...$floats) : float
{
return array_sum($floats);
}
echo SumFloats(1.1,2.5,3);
?>
Run the script to have the result, the float number 6.6
, printed out. In this case, the int
values get converted to float
.
Our next example will show how to use strict scalar type declarations with float type. Create a script sumfloats.php and define a function with two parameters of type float
and return type int
. Return type declaration is another new feature and is discussed in more detail later on, we will just assume they are ok for this example. The function returns a value by adding its two arguments. Invoke then the function with one argument of type int
and the other of type string
:
<?php
declare(strict_types=1);
function SumFloats(float $a, float $b) : int
{
return $a + $b;
}
echo SumFloats(1,'3');
?>
If you run the script, a TypeError
is generated indicating that an argument passed to a function must be of type float
while a string
was given.
Uncaught TypeError: Argument 2 passed to SumFloats() must be of the type float, string given
If you remove the declare directive for strict mode and run the script again, coercive mode will give you an output value of 4.
Scalar type declarations may be used with strings. Create a script reverse.php and add a function to it that takes a string
parameter, reverses it, and returns the resulting string
. Using a try/catch block, invoke the function with a floating-point value 3.5
:
<?php
function Reverse(string $a)
{
return strrev($a);
}
try{
echo Reverse(3.5);
}catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}
?>
If you run the script, you will get a value of 5.3
in coercive mode. If you add the directive declare(strict_types=1)
; for strict mode and run the script again, an Error
is raised:
Error: Argument 1 passed to Reverse() must be of the type string, float given
Strict typing for scalar type declarations only applies to function calls from within the file in which strict typing is enabled and not to function calls from another file that does not declare strict typing. Similarly, if the file that makes the function call also has strict typing enabled, strict mode is used.
To demonstrate, create a PHP script reverse_2.php with strict mode enabled. Add a function (called Reverse
) that reverses and returns a string
parameter value:
<?php
declare(strict_types=1);
function Reverse(string $a)
{
return strrev($a);
}?>
Create now another script reverse_1.php that requires the reverse_2.php script and invokes its Reverse function with a floating point value:
<?php
require_once('reverse_2.php');
echo Reverse(3.5);
?>
Run the reverse_1.php script. As strict mode is enabled in reverse_2.php, one might expect that a TypeError
would be generated as the function that expects a string
value is invoked with a floating point value. But reverse_1.php uses weak typing and a floating point value is returned with an output of 5.3.
On the contrary, if strict mode is enabled in reverse_1.php, strict typing is applied and a TypeError
generated:
Uncaught TypeError: Argument 1 passed to Reverse() must be of the type string, float given
Our next example deals with scalar type declarations for the boolean type. Create a script test.php with strict mode enabled and add a function that accepts a parameter of type bool
and simply returns the unaltered parameter value. Invoke the function with a string value ‘true’:
<?php
declare(strict_types=1);
function test(bool $param) {return $param;}
echo test('true')
?>
Running the script in a browser will give you a TypeError
.
Uncaught TypeError: Argument 1 passed to test() must be of the type bool, string given
If the declare
directive for strict mode is commented out or removed and the script is run again, coercive mode is applied. In this case, the string
‘true’ gets converted to the bool
value true
and the output will be 1
.
Now, we will go deeper about the use of NULL
values with scalar type strings.
Create a script string_null.php containing two functions, each of which takes a string argument. One of the functions has the default argument value set to NULL
and the other function has no default value set. Invoke each of the functions with a string
value, no value, and null
value:
<?php
function string_null_1(string $str) {
var_dump($str);
}
function string_null_2(string $str = NULL) {
var_dump($str);
}
string_null_1('a');
string_null_2('b');
string_null_1();
string_null_2();
string_null_2(null);
string_null_1(null);
?>
If you run the script, string_null_1 will generate an error when invoked with no argument.
Uncaught ArgumentCountError: Too few arguments to function string_null_1(), 0 passed in
Comment out the function call that generates the preceding message and run the script again. You will see that the function calls providing string
type arguments output a string, as expected. Calling string_null_2
, which has a default value set to NULL
, with no arguments outputs NULL
. Calling string_null_2
with a NULL
value as argument also outputs NULL
, as expected. Calling string_null_1()
passing NULL
generates a TypeError
, instead, since the NULL
argument does not get converted to a string
in coercive mode.
Return Type Declarations
As we briefly mentioned above, PHP 7.0 added support for return type declarations, which are similar to parameter type declarations. The same PHP types may be used with return type declarations as with parameter type declarations. To demonstrate the use of return type declarations, create a script reverse_return.php that declares a function with a parameter of type string and string return type.
<?php
function Reverse(string $a) : string
{
return strrev($a);
}
try{
echo Reverse('hello');
}catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}?>
Invoke the function with input value “hello
” and the reversed string olleh
gets output. The strict mode directive that is used for scalar type declarations is also applied to return type declarations. To demonstrate this, create a script reverse_return_strict.php and add the strict mode directive at the beginning. Add then a function that takes a string parameter and returns a string
value. Instead of returning a string value, make the actual value returned be an integer:
<?php
declare(strict_types=1);
function Reverse(string $a) : string
{
return 5;
}
try{
echo Reverse("hello");
}catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}
?>
Invoke the function with a string value. Running the script will generate an error:
Error: Return value of Reverse() must be of the type string, int returned
If you remove the strict mode declaration, thus switching to coercive mode, and run the script again, you will see the value ‘5’ is printed out. In this case, the int
value returned is cast to a string
due to weak typing.
In coercive mode, the return value gets converted to the expected return type if needed. Modify the script and declare the function return type to be an int
, but actually return a string ‘5’, instead.
<?php
function Reverse(string $a) : int
{
return '5';
}
try{
echo Reverse("hello");
}catch (TypeError $e) {
echo 'Error: '.$e->getMessage();
}
?>
Invoke the function passing a string value. In this case, the int
type value 5 is returned after being converted from the string value ‘5’. For the conversion to be made in coercive mode, the returned value has to be convertible to the declared return type. As an example of that, if you declare an int return type and return the string ‘five’, an error is generated.
Return value of Reverse() must be of the type int, string returned
While scalar type declarations are new in PHP 7, class type declarations are not supported yet. Class types may be used in return type declarations, though, as we shall demonstrate next.
Create a script return_obj.php and declare a class Catalog
including some variables typical of a magazine catalog. Instantiate the class and set values for its variables. Declare then a function with return type Catalog
taking a single parameter of type Catalog
. In the body of this function, just return the input argument itself:
function getCatalog(Catalog $catalog): Catalog {
return $catalog;
}
Invoke the function with a Catalog
class object and then output the returned value.
var_dump(getCatalog($Catalog1));
The return_obj.php script is listed:
<?php
class Catalog
{
public $title;
public $edition;
}
$Catalog1 = new Catalog();
$Catalog1->title = 'Oracle Magazine';
$Catalog1->edition = 'January-February2018';
function getCatalog(Catalog $catalog): Catalog {
return $catalog;
}
var_dump(getCatalog($Catalog1));
?>
Running the script will output the Catalog
class object field values, as shown in Figure 18.
object(Catalog)#1 (2) { ["title"]=> string(15) "Oracle Magazine" ["edition"]=> string(20) "January-February2018" }
As we discussed in the first article in this series, Getting started and OOP improvements, class inheritance in PHP 7.2 supports one-level return type covariance and contravariance to no type. As you remember, covariance for return type makes it possible to provide a narrower return type, while contravariance for parameter types makes it possible to provide a more generic parameter type. PHP 7.4 added full support for covariance and contravariance.
To demonstrate this, create a script return_type_inheritance.php. Add a class Catalog
with a function declaring a parameter of type string and no return type. Create another class CatalogMagazine
that extends the Catalog
class. The return type of the function is string
and the parameter type is omitted, relying on PHP 7 parameter type widening support. Instantiate each class and invoke the function to output the value returned:
<?php
class Catalog
{
public function printItem(string $string)
{
return 'Catalog: ' . $string . PHP_EOL;
}
}
class CatalogMagazine extends Catalog
{
public function printItem($string) : string
{
return 'CatalogMagazine: ' . $string . PHP_EOL;
}
}
$catalog = new Catalog();
$catalogMagazine = new CatalogMagazine();
echo $catalog->printItem('Catalog');
echo $catalogMagazine->printItem('CatalogMagazine');
?>
Running the script will output the return value of the functions defined in each class object:
Catalog: Catalog CatalogMagazine: CatalogMagazine
Nullable Types
It is not uncommon for null values to be passed as function parameters or returned from a function. The null
type in PHP has only one value and it is case-insensitive NULL
.
PHP 7.1 has added support for nullable parameter types and nullable return types. Prefix a parameter or return type with a question mark ?
to make it nullable. To demonstrate the use of the nullable type create a script hello-nullable.php. Define a function hello()
specifying a nullable return type. Nullable does not imply the function has to return null, though, so let’s return an actual value:
function hello(): ?string
{
return 'Hello';
}
Define now another function with nullable return type that actually returns NULL
:
function hello_return_null(): ?string
{
return null;
}
Finally, define a function with a nullable parameter type:
<?php
function hello(): ?string
{
return 'Hello';
}
echo hello();
echo "<br/>";
function hello_return_null(): ?string
{
return null;
}
echo hello_return_null();
echo "<br/>";
function hello_null_arg(?string $name)
{
return 'Hello';
}
echo hello_null_arg(null);
echo "<br/>";
?>
Running the script will produce the following output:
Hello
Hello
The second function call produces no output because echo
converts its argument to a to string and null does not have any corresponding string
value. If var_dump()
is used instead of echo a NULL
value should get the following output:.
Hello
NULL
Hello
Next, we shall demonstrate with an example that if the return type of a function is a class type, null cannot be returned. Create a script return_null.php and copy the following listing:
<?php
class Catalog
{
public $title;
public $edition;
}
$Catalog1 = new Catalog();
$Catalog1->title = 'Oracle Magazine';
$Catalog1->edition = 'January-February2018';
function getCatalog(?Catalog $catalog): ?Catalog {
return $catalog;
}
function getCatalog_2(?Catalog $catalog): ?Catalog {
return null;
}
function getCatalog_3(?Catalog $catalog): Catalog {
return $catalog;
}
var_dump(getCatalog(null));
var_dump(getCatalog_2(null));
var_dump(getCatalog_3(null));
?>
The script declares a class Catalog
with two fields. The script creates an instance of the class and sets its field values to initialize it. All three functions in the script declare a nullable parameter of type Catalog
. Two of the functions have nullable return type Catalog
and one function has non-nullable return type Catalog
. Each of the functions is invoked with a null argument and the call is enclosed in var_dump()
.
As the output indicates, if the return type is nullable and a null argument is passed, the return value is null whether the actual argument or null is returned. But if the return type is a class type such as Catalog
and null is returned, an error is generated indicating that return value must be an instance of the class type, in the example Catalog
:
NULL NULL
Uncaught TypeError: Return value of getCatalog_3() must be an instance of Catalog, null returned
Using void as Return Type for Functions
As mentioned, support for return type declarations was added in PHP 7.0, while PHP 7.1 introduced the void
return type. In a function returning void, the return statement should either be empty or omitted altogether. NULL
is not to be confused with void
type. NULL
is a value for the null type, while void implies the absence of a value.
To demonstrate the use of a void
return type, create a script hello-void.php and copy the following listing into that file:
<?php
function hello(): void
{
echo 'Hello';
return;
}
echo hello();
echo "<br/>";
?>
The script declares a function called hello()
with return type void
. The function outputs a ‘Hello’ string and has an empty return statement. If the return type is void
the function must not return a value. Run the script, “Hello” is output.
Next, we demonstrate that a function with return type void
is not allowed to return a value, not even NULL
. Create a script return_void.php and declare a class Catalog
containing a function with return type void that returns NULL
. Invoke the function passing an instance of Catalog
as an argument. The return_void.php script is listed here:
<?php
class Catalog
{
public $title;
public $edition;
}
$Catalog1 = new Catalog();
$Catalog1->title = 'Oracle Magazine';
$Catalog1->edition = 'January-February2018';
function getCatalog(Catalog $catalog): void {
return NULL;
}
var_dump(getCatalog($Catalog1));
?>
Running the script will output an error message.
A void function must not return a value (did you mean "return;" instead of "return null;"?)
Modify the script slightly so that the function has an empty return
statement, which is valid for the void
return type. Invoke the function with an instance of Catalog
as an arg.
function getCatalog(Catalog $catalog): void {
return;
}
var_dump(getCatalog($Catalog1));
In this case, a value of NULL
is returned since we used an empty return statement, as var_dump
makes clear.
New iterable type
The iterable
is a new compound type in PHP 7.1. Pseudo types are keywords used for types or values that an argument may have. The iterable
type may be used as parameter type or return type. It accepts an array or an object that implements the Traversable
interface, both of which can be iterated over using foreach
.
First, we shall demonstrate how to use iterable
with an array. Create a script iter.php in which declare a function with parameter type iterable. iterable
type parameters may declare a default value that is NULL
or an array. Within the function iterate over the iterable using foreach()
and output its values. Create an array and invoke the function using the array as its argument. The iter.php is listed.
<?php
$catalog = ['Oracle Magazine','Java Magazine','PHP Magazine'];
function iterator(iterable $iter)
{
foreach ($iter as $val) {
echo $val;
echo "<br/>";
}
}
iterator($catalog);
?>
Run the script to output the array values:
Oracle Magazine
Java Magazine
PHP Magazine
An iterable
also accepts a class object that implements the Traversable
interface. To demonstrate this, create a script iter_traversable.php and declare a class that implements the IteratorAggregate
interface, which further extends the Traversable
interface. Declare three class properties.
public $journal1 = "Oracle Magazine";
public $journal2 = "Java Magazine";
public $journal3 = "PHP Magazine"
Add a class constructor that implements the interface function abstract public Traversable getIterator ( void ).
Let’s call this class catalogData
. In the same script, also declare a function with parameter type iterable
. Within this function, use foreach
to iterate over the iterable
parameter and output its values:
function iterator(iterable $iter)
{
foreach($iter as $key => $value) {
var_dump($key, $value);
echo "\n";
}
}
Finally, invoke the function with an instance of the class catalogData
as an argument:
$obj = new catalogData;
iterator($obj);
The iter_traversable.php script is listed:
<?php
class catalogData implements IteratorAggregate {
public $journal1 = "Oracle Magazine";
public $journal2 = "Java Magazine";
public $journal3 = "PHP Magazine";
public function __construct() {
}
public function getIterator() {
return new ArrayIterator($this);
}
}
$obj = new catalogData;
function iterator(iterable $iter)
{
foreach($iter as $key => $value) {
var_dump($key, $value);
echo "\n";
}
}
iterator($obj);
?>
Now, run the script to output the key/value pairs in the iterable:
string(8) "journal1" string(15) "Oracle Magazine" string(8) "journal2" string(13) "Java Magazine" string(8) "journal3" string(12) "PHP Magazine"
The iterable
type supports full contravariance (for parameter type) and covariance (for return type). Covariance and Contravariance are discussed in detail in an earlier article PHP 7 — Getting Started and OOP Improvements. Full contravariance implies that parameter types array
and Traversable
may be widened to iterable
. Full covariance implies that return type iterable
may be narrowed to array
or Traversable
. Next, we shall demonstrate covariance and contravariance with iterable using an example. Create a script iter_extend_ret_type.php and declare a class containing an iterator function with an array parameter and nullable iterable return type. Within the class, iterate over the array
argument using foreach
and output its values. Declare a class that extends the first one and overrides the iterator
function with a function that has an iterable
parameter and nullable array
return type. Create an instance of the extending class and invoke its iterator function. The script is listed here:
<?php
class ClassA{
function iterator(array $arr) : ?iterable
{
foreach ($arr as $val) {
echo $val;
echo "<br/>";
return null;
}
}
}
class ClassB extends ClassA{
function iterator(iterable $iter) : ?array
{
foreach ($iter as $val) {
echo $val;
echo "<br/>";
}
return null;
}
}
$catalog = ['Oracle Magazine','Java Magazine','PHP Magazine'];
$classB=new ClassB();
$classB->iterator($catalog);
?>
Run the script, which will output:
Oracle Magazine
Java Magazine
PHP Magazine
Functions with return type iterable
may also be used as generators. As an example, create a script iterable_gen.php and create and invoke a generator function with return type iterable
. Yield some values in the generator function and return an array
. Subsequently, output the values yielded by the generator function. Also output the generator function return value using getReturn()
function to obtain the return value:
<?php
function generator(): iterable {
yield 'a';
yield 'b';
yield 'c';
return ['a','b','c'];
}
$gen = generator();
foreach ($gen as $value) {
echo "$value\n";
}
var_dump($gen->getReturn());
?>
Run the script to output the values yielded by the generator function.
a b c array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" }
Typed Properties
Version 7 has made several improvements to PHP's type system. PHP 7.4 adds support for typed properties, using which you can declare types for class properties. Class properties do nor require you to explicitly declare getter/setter methods for them. Some of their salient characteristics are:
- Types may be declared on
static
properties as well. - References to typed properties are supported.
- The typed properties are affected by the
strict_types
directive just as the parameter types and return types are. - Types may be used with
var
notation. - Default values for typed properties may be declared.
- The type of multiple properties may be declared in a single declaration.
- Implicit
int
tofloat
cast is made. - The type for a nullable property may be declared.
- A class property of type
callable
orvoid
cannot be declared.
As an example, consider the following class called Catalog
that illustrates several of the preceding characteristics:
<?php
declare(strict_types=1);
class Catalog {
public int $catalogid,$journalid;
public ?string $journal=null;
public static string $edition="January-February 2020";
var bool $flag;
public float $f=1;
public function __construct(int $catalogid,int $journalid,string $journal,bool $flag)
{
$this->catalogid = $catalogid;
$this->journalid = $journalid;
$this->journal = $journal;
$this->flag = $flag;
}
}
$c = new Catalog(123,345,"PHP Magazine",true);
echo "Catalogid: ".$c->catalogid."\n";
echo "Journalid: ".$c->journalid."\n";
echo "Journal: ".$c->journal."\n";
echo "Flag: ".$c->flag."\n";
echo "Edition: ".Catalog::$edition."\n";
?>
Run now the script, whose output is shown in Figure 2.
Figure 2. Output illustrating use of Typed properties
To demonstrate the use of properties along with strict-type mode, consider the following script that sets strict_types
to 1 and declares a class property called $catalogid
of type int
. Then try to assign the $catalogid
property a string
value:
<?php
declare(strict_types=1);
class Catalog {
public int $catalogid;
}
$c = new Catalog();
$c->catalogid = "123";
?>
When the script is run, the following TypeError
is thrown:
Uncaught TypeError: Typed property Catalog::$catalogid must be int, string used
If you define, no TypeError
is thrown. The important distinction to note here is that the assigned value must satisfy the strict_types
mode at the write-location of the property. In other terms, the strict_types
mode at the property declaration location is not relevant. If strict_types
mode is set to 1 at the write-location, the assigned value must be of the declared type. To demonstrate the use of different modes, we shall use two different files a.php and b.php with strict_types
mode set to 1 and 0 respectively. The scripts also demonstrate the following characteristics of references when used with typed properties:
- An uninitialized-nullable property may be accessed by reference
- An uninitialized non-nullable property cannot be accessed by reference
- An array may be accessed by reference.
In a.php, set strict_types
mode to 1 and declare a class A
containing a typed class property called $a
of type int
. Make sure the a.php script also declare an array, a nullable property and a non-nullable property:
<?php
declare(strict_types=1);
class A {
public int $a;
public array $array = [3, 1, 2];
public ?int $x;
public int $y;
}
In a second file, b.php, include a.php and set strict_types
mode to 0
. Instantiate class A,
then use var_dump
to output this instance’s $a
property value, which is shown in the following listing after the comment //
. Then, access the array
type property through its reference, and finally, sort and output it.
Now access the int
type variable $a
through its reference and assign it string value “1”. Output the variable $a
value using var_dump
and you will see no TypeError
is thrown. This is because th value stored in $a
is cast to its type, int
.
Also notice you can access the uninitialized nullable property $x
through its reference. In such a case, it will be transparently initialized to NULL
. On the contrary, if you try to access the uninitialized non-nullable property $y
, you will get a TypeError
.
<?php
declare(strict_types=0);
include 'a.php';
$a = new A;
$a->a = "1";
var_dump($a->a); // int(1)
sort($a->array);
var_dump($a->array);// array(3) { [0]=> int(1) [1]=> //int(2) [2]=> int(3) }
$x =& $a->x; // Initialized to null
$y =& $a->y; //TypeError Uncaught Error: Cannot access //uninitialized non-nullable property A::$y by reference
Next, we shall discuss another important characteristic of typed properties that has to do with type invariance.
- The type of a non-private property cannot be changed in a derived class. A non-private property type cannot be added or removed either.
- The type of a private property can be changed in a derived class. Private property types may be added or removed.
To demonstrate type invariance, declare a class called A
that contains a private variable $a
of type int
, a public variable $b
of type string
, a nullable public variable $c
of type int
, and a public variable $d
of type string.
Also declare a void
type property called $v
to verify the void
type cannot be used with properties.
<?php class A {
private int $a;
public string $b;
public ?int $c;
public string $d;
public void $v;//Property A::$v cannot have type void
}
Declare now a class B
that extends class A and changes the types of its class properties. Change the type of the private property $a
from int
to string
and make it public, which is supported. If you try to change the type of the public property $b
from string
to int
; the type of the public property $c
nullable int
to int;
or to omit the type of the public property $d
, you will get errors. The error messages output are shown below as comments.
class B extends A {
public string $a;
public int $b; // Type of B::$b must be string (as in class A)
public int $c; // Type of B::$c must be ?int (as in class A)
public $d; // Type of B::$d must be string (as in class A)
}
Summary
In this third article in our series on PHP 7.x, we discussed new features in PHP’s type system.
PHP 7.0 added support for scalar type declarations for string,int,float
, and bool
types. PHP also 7.0 added support for return type declarations to be used in the return
statement.
PHP 7.1 added support for the null
type, which has only one value, NULL
, and for a return type called void
, representing the absence of any value. PHP 7.1 also added support for a new type called iterable
. While the void
type may be used only as return type, iterable
can be used as a parameter or a return type.
Typed properties were added in PHP 7.4, which enable to explicitly declare types for class properties.
In the next article in the series we shall explore new features for PHP functions.
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.