PHP Language Specification

The PHP Language Specification intends to provide a complete and concise definition of the syntax and semantics of the PHP programming language.

Colophon

The PHP Language Specification was initially written in July 2014 by Facebook, Inc.

Facebook has dedicated all copyright to this specification to the public domain worldwide under the CC0 Public Domain Dedication located at http://creativecommons.org/publicdomain/zero/1.0/. This specification is distributed without any warranty.

The PHP Language Specification is maintained at https://github.com/php/php-langspec.

phplang.org is Copyright 2019, PHP Community Foundation, Inc..

The source code files used to generate phplang.org are licensed under the Apache License, Version 2.0. Original content on phplang.org is licensed under the Creative Commons Attribution 4.0 International License.

The source repository for phplang.org is located at https://github.com/phpcommunity/phplang.org.

This documentation was generated on 5 December 2023 at 16:00 UTC from php/php-langspec@4c19272 and phpcommunity/phplang.org@295a059.

Introduction

This specification is intended to provide a complete and concise definition of the syntax and semantics of the PHP language, suitable for use by the following:

  • Implementers of a PHP compiler.
  • Implementers of a test suite for the PHP language.
  • Programmers writing PHP code.

For now, the runtime library has been excluded, as that is documented at www.php.net. However, the document can contain references to the library functions, usually in the form of links to http://www.php.net.

Conformance

In this specification, “must” is to be interpreted as a requirement on an implementation or on a program; conversely, “must not” is to be interpreted as a prohibition.

If a “must” or “must not” requirement that appears outside of a constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this specification by the words “undefined behavior” or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe “behavior that is undefined”.

The word “may” indicates “permission”, and is never used to mean “might”.

A strictly conforming program must use only those features of the language described in this specification. In particular, it must not produce output or exhibit behavior dependent on any unspecified, undefined, or implementation-defined behavior.

A conforming implementation must accept any strictly conforming program. A conforming implementation may have extensions, provided they do not alter the behavior of any strictly conforming program.

A conforming program is one that is acceptable to a conforming implementation.

A conforming implementation must be accompanied by a document that defines all implementation-defined characteristics and all extensions.

Some Syntax sections are followed by a Constraints section, which further restricts the grammar. After issuing a diagnostic for a constraint violation, a conforming implementation may continue program execution. In some cases, such continuation behavior is documented (for example, what happens when passing too few arguments to a function). Making such things constraint violations simply forces the issuance of a diagnostic; it does not require that program execution terminate.

This specification contains explanatory material—called informative or non-normative text—that, strictly speaking, is not necessary in a formal language specification. Examples are provided to illustrate possible forms of the constructions described. References are used to refer to related clauses. Notes and Implementer Notes are provided to give advice or guidance to implementers or programmers. Informative annexes provide additional information and summarize the information contained in this specification. All text not marked as informative is normative.

Certain features are marked as deprecated. While these are normative for the current edition of this specification, they are not guaranteed to exist in future revisions. Usually, they are old approaches that have been superseded by new ones, and use of the old approach is discouraged. (Examples of this include the use of braces ({ }) for subscripting, and the use of old-style constructor names).

Terms and Definitions

For the purposes of this document, the following terms and definitions apply:

argument
a value passed to a function, that is intended to map to a corresponding parameter.
behavior
external appearance or action.
behavior, implementation-defined
behavior specific to an implementation, where that implementation must document that behavior.
behavior, undefined
behavior which is not guaranteed to produce any specific result. Usually follows an erroneous program construct or data.
behavior, unspecified
behavior for which this specification provides no requirements.
constraint
restriction, either syntactic or semantic, on how language elements can be used.
error, fatal
a condition in which the engine cannot continue executing the script and must terminate.
error, fatal, catchable
a fatal error that can be caught by a user-defined handler.
error, non-fatal
an error that is not a fatal error and allows for the engine to continue execution.
lvalue
an expression that designates a location that can store a value.
lvalue, modifiable
an lvalue whose value can be changed.
lvalue, non-modifiable
an lvalue whose value cannot be changed.
notice
an informational message informing user of the code that may not work as intended.
parameter
a variable declared in the parameter list of a function that is intended to map to a corresponding argument in a call to that function.
PHP Run-Time Engine
the software that executes a PHP program. Referred to as the Engine throughout this specification.
value
a primitive unit of data operated by the Engine having a type and potentially other content depending on the type.

Other terms are defined throughout this specification, as needed, with the first usage being typeset like this.

Basic Concepts

Program Structure

A PHP program consists of one or more source files, known formally as scripts.

script:
   script-section
   script   script-section

script-section:
   textopt   start-tag   statement-listopt   end-tagopt   textopt

start-tag:
   <?php
   <?=

end-tag:
   ?>

text:
   arbitrary text not containing any of   start-tag   sequences

All of the sections in a script are treated as though they belonged to one continuous section, except that any intervening text is treated as though it were a string literal given to the echo statement.

A script can import another script via a script inclusion operator.

statement-list is defined in statements section.

The top level of a script is simply referred to as the top level.

If <?= is used as the start-tag, the Engine proceeds as if the statement-list started with an echo statement.

Program Start-Up

A program begins execution at the start of a script designated in some unspecified manner. This script is called the start-up script.

Once a program is executing, it has access to certain environmental information, which may include:

  • The number of command-line arguments, via the predefined variable $argc.
  • A series of one or more command-line arguments as strings, via the predefined variable $argv.
  • A series of environment variable names and their definitions.

The exact set of the environment variables available is implementation-defined and can vary depending on the type and build of the Engine and the environment in which it executes.

When a top level is the main entry point for a script, it gets the global variable scope. When a top level is invoked via include/require, it inherits the variable scope of its caller. Thus, when looking at one script’s top level in isolation, it’s not possible to tell statically whether it will have the global variable scope or some local variable scope. It depends on how the script is invoked and it depends on the runtime state of the program when it’s invoked.

The implementation may accept more than one start-up script, in which case they are executed in implementation-defined order and share the global environment.

Program Termination

A program may terminate normally in the following ways:

  • Execution reaches the end of the start-up script. In case of the multiple start-up scripts, the execution reaches the end of the last of them.
  • A return statement in the top level of the last start-up script is executed.
  • The intrinsic exit is called explicitly.

The behavior of the first two cases is equivalent to corresponding calls to exit.

A program may terminate abnormally under various circumstances, such as the detection of an uncaught exception, or the lack of memory or other critical resource. If execution reaches the end of the start-up script via a fatal error, or via an uncaught exception and there is no uncaught exception handler registered by set_exception_handler, that is equivalent to exit(255). If execution reaches the end of the start-up script via an uncaught exception and an uncaught exception handler was registered by set_exception_handler, that is equivalent to exit(0). It is unspecified whether object destructors are run. In all other cases, the behavior is unspecified.

__halt_compiler

PHP script files can incorporate data which is to be ignored by the Engine when compiling the script. An example of such files are PHAR files.

In order to make the Engine ignore all the data in the script file starting from certain point, __halt_compiler(); construct is used. This construct is not case-sensitive.

The __halt_compiler(); construct can only appear on the top level of the script. The Engine will ignore all text following this construct.

The value of the __COMPILER_HALT_OFFSET__ constant is set to the byte offset immediately following the ; character in the construct.

Example

// open this file
$fp = fopen(__FILE__, 'r');

// seek file pointer to data
fseek($fp, __COMPILER_HALT_OFFSET__);

// and output it
var_dump(stream_get_contents($fp));

// the end of the script execution
__halt_compiler(); the file data which will be ignored by the Engine

The Memory Model

General

This section and those immediately following it describe the abstract memory model used by PHP for storing variables. A conforming implementation may use whatever approach is desired as long as from any testable viewpoint it appears to behave as if it follows this abstract model. The abstract model makes no explicit or implied restrictions or claims about performance, memory consumption, and machine resource usage.

The abstract model presented here defines three kinds of abstract memory locations:

  • A variable slot (VSlot) is used to represent a variable named by the programmer in the source code, such as a local variable, an array element, an instance property of an object, or a static property of a class. A VSlot comes into being based on explicit usage of a variable in the source code. A VSlot contains a pointer to a VStore.
  • A value storage location (VStore) is used to represent a program value, and is created by the Engine as needed. A VStore can contain a scalar value such as an integer or a Boolean, or it can contain a handle pointing to an HStore.
  • A heap storage location (HStore) is used to represent the contents of a composite value, and is created by the Engine as needed. HStore is a container which contains VSlots.

Each existing variable has its own VSlot, which at any time points to a VStore. A VSlot can be changed to point to different VStores over time. Multiple VSlots may simultaneously point to the same VStore. When a new VSlot is created, a new VStore is also created and the VSlot is initially set to point to the new VStore.

A VStore can be changed to contain different values over time. Multiple VStores may simultaneously contain handles that point to the same HStore. When a VStore is created it initially contains the value NULL unless specified otherwise. In addition to containing a value, VStores also carry a type tag that indicates the type of the VStore’s value. A VStore’s type tag can be changed over time. The tags for the values include types matching the Engine types, and may include other tags defined by the implementation, provided that these tags are not exposed to the user.

An HStore represents the contents of a composite value, and it may contain zero or more VSlots. At run time, the Engine may add new VSlots and it may remove and destroy existing VSlots as needed to support adding/removing array elements (for arrays) and to support adding/removing instance properties (for objects). HStores support access to VSlots contained in them by integer or case-sensitive string keys. The exact manner of how VSlots are stored and managed within the HStore is unspecified.

HStore may contain other information besides VSlots. For example, HStore for objects also contains information about object’s class. The implementation may also add other information to HStore as needed.

An HStore’s VSlots (i.e., the VSlots contained within the HStore) point to VStores, and each VStore contains a scalar value or a handle to an HStore, and so on through arbitrary levels, allowing arbitrarily complex data structures to be represented. For example, a singly linked list might consist of a variable called $root, which is represented by a VSlot pointing to a VStore containing a handle to the first node. Each node is represented by an HStore that contains the data for that node in one or more VSlots, as well as a VSlot pointing to VStore containing a handle to the next node. Similarly, a binary tree might consist of a variable called $root, which is represented by a VSlot pointing to a VStore containing a handle to the root node. Each node is represented by an HStore that contains the data for that node in one or more VSlots, as well as a pair of VSlots pointing to VStores containing the handles to the left and right branch nodes. The leaves of the tree would be VStores or HStores, as needed.

VSlots cannot contain pointers to VSlots or handles to HStores. VStores cannot contain pointers to VSlots or VStores. HStores cannot directly contain any pointers or handles to any abstract memory location; HStores can only directly contain VSlots.

Here is an example demonstrating one possible arrangement of VSlots, VStores, and HStores:

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
                                                           V            V
                                                      [VStore int 1]  [VStore int 3]

In this picture the VSlot in the upper left corner represents the variable $a, and it points to a VStore that represents $a’s current value, which is a object. This VStore contains a handle pointing to an HStore which represents the contents of an object of type Point with two instance properties $x and $y. The HStore contains two VSlots representing instance properties $x and $y, and each of these VSlots points to a distinct VStore which contains an integer value.

Even though resources are not classified as scalar values, for the purposes of the memory model they are assumed to behave like scalar values, while the scalar value is assumed to be the the resource descriptor.

Implementation Notes: php.net’s implementation can be mapped roughly onto the abstract memory model as follows: zval pointer => VSlot, zval => VStore, HashTable => HStore, and zend_object/zend_object_handlers => HStore. Note, however, that the abstract memory model is not intended to exactly match the php.net implementation’s model, and for generality and simplicity there are some superficial differences between the two models.

For most operations, the mapping between VSlots and VStores remains the same. Only the following program constructs can change a VSlot to point to different VStore, all of which are byRef-aware operations and all of which (except unset) use the & punctuator:

Reclamation and Automatic Memory Management

The Engine is required to manage the lifetimes of VStores and HStores using some form of automatic memory management. In particular, when a VStore or HStore is created, memory is allocated for it.

Later, if a VStore or HStore becomes unreachable through any existing VSlot, they become eligible for reclamation to release the memory they occupy. The engine may reclaim a VStore or HStore at any time between when it becomes eligible for reclamation and the end of the script execution.

Before reclaiming an HStore that represents an object, the Engine should invoke the object’s destructor if one is defined.

The Engine must reclaim each VSlot when the storage duration of its corresponding variable ends, when the variable is explicitly unset by the programmer, or when the script exits, whichever comes first. In the case where a VSlot is contained within an HStore, the engine must immediately reclaim the VSlot when it is explicitly unset by the programmer, when the containing HStore is reclaimed, or when the script exits, whichever comes first.

The precise form of automatic memory management used by the Engine is unspecified, which means that the time and order of the reclamation of VStores and HStores is unspecified.

A VStore’s refcount is defined as the number of unreclaimed VSlots that point to that VStore. Because the precise form of automatic memory management is not specified, a VStore’s refcount at a given time may differ between conforming implementations due to VSlots, VStores, and HStores being reclaimed at different times. Despite the use of the term refcount, conforming implementations are not required to use a reference counting-based implementation for automatic memory management.

In some pictures below, storage-location boxes are shown as (dead). For a VStore or an HStore this indicates that the VStore or HStore is no longer reachable through any variable and is eligible for reclamation. For a VSlot, this indicates that the VSlot has been reclaimed or, in the case of a VSlot contained with an HStore, that the containing HStore has been reclaimed or is eligible for reclamation.

Assignment

General

This section and those immediately following it describe the abstract model’s implementation of value assignment and byRef assignment. Value assignment of non-array types to local variables is described first, followed by byRef assignment with local variables, followed by value assignment of array types to local variables, and ending with value assignment with complex left-hand side expressions, and byRef assignment with complex expressions on the left- or right-hand side.

Value assignment and byRef assignment are core to the PHP language, and many other operations in this specification are described in terms of value assignment and byRef assignment.

Value Assignment of Scalar Types to a Local Variable

Value assignment is the primary means by which the programmer can create local variables. If a local variable that appears on the left-hand side of value assignment does not exist, the engine will bring a new local variable into existence and create a VSlot and initial VStore for storing the local variable’s value.

Consider the following example of value assignment of scalar values to local variables:

$a = 123;

$b = false;
[VSlot $a *]-->[VStore int 123]

[VSlot $b *]-->[VStore bool false]

Variable $a comes into existence and is represented by a newly created VSlot pointing to a newly created VStore. Then the integer value 123 is written to the VStore. Next, $b comes into existence represented by a VSlot and corresponding VStore, and the Boolean value false is written to the VStore.

Next consider the value assignment $b = $a:

[VSlot $a *]-->[VStore int 123]

[VSlot $b *]-->[VStore int 123]

The integer value 123 is read from $a’s VStore and is written into $b’s VStore, overwriting its previous contents. As we can see, the two variables are completely independent, each has its own VStore containing the integer value 123. Value assignment reads the contents of one VStore and overwrites the contents of the other VStore, but the relationship of VSlots to VStores remains unchanged. Changing the value of $b has no effect on $a, and vice versa.

Using literals or arbitrarily complex expressions on the right hand side of value assignment value works the same as it does for variables, except that the literals or expressions don’t have their own VSlots or VStores. The scalar value or handle produced by the literal or expression is written into the VStore of the left hand side, overwriting its previous contents.

Implementation Notes: For simplicity, the abstract model’s definition of value assignment never changes the mapping from VSlots to VStores. However, the conforming implementation is not required to actually keep separate memory allocations for both variables, it is only required to behave as if they were independent, e.g. writes to one VStore should not change the content of another.

For example, the php.net implementation’s model, which in some cases will set two variable slots to point to the same zval when performing value assignment, produces the same observable behavior as the abstract model presented here.

To illustrate the semantics of value assignment further, consider ++$b:

[VSlot $a *]-->[VStore int 123]

[VSlot $b *]-->[VStore int 124 (123 was overwritten)]

Now consider $a = 99:

[VSlot $a *]-->[VStore int 99 (123 was overwritten)]

[VSlot $b *]-->[VStore int 124]

In both of these examples, one variable’s value is changed without affecting the other variable’s value. While the above examples only demonstrate value assignment for integer and Boolean values, the same mechanics apply for all scalar types.

Note that as string values are scalar values, the model assumes the whole string representation, including string characters and its length, is contained within the VStore. This means that the model assumes whole string data is copied when the string is assigned.

$a = 'gg';

$b = $a;
[VSlot $a *]-->[VStore string 'gg']

[VSlot $b *]-->[VStore string 'gg']

$a’s string value and $b’s string values are distinct from each other, and mutating $a’s string will not affect $b. Consider ++$b, for example:

[VSlot $a *]-->[VStore string 'gg']

[VSlot $b *]-->[VStore string 'gh']

Implementation Notes: The conforming implementation may use an actual representation where string characters are stored outside the structure representing the VStore and are not copied immediately on assignment, for performance reasons. Applications in PHP are often written to assume that value assignment of strings is a rather inexpensive operation. Thus, it is common for an implementation to use a deferred copy mechanism to reduce the cost of value assignment for strings. Deferred copy mechanisms work by not copying a string during value assignment and instead allowing multiple variables to share the string’s contents indefinitely until a mutating operation (such as the increment operator) is about to be executed on the string, at which time some or all of the string’s contents are copied. A conforming implementation may choose to defer copying a string’s contents for value assignment so long as it has no observable effect on behavior from any testable viewpoint (excluding performance and resource consumption).

Value Assignment of Objects to a Local Variable

To demonstrate value assignment of objects to local variables, consider the case in which we have a Point class that supports a two-dimensional Cartesian system. An instance of Point contains two instance properties, $x and $y, that store the x- and y-coordinates, respectively. A constructor call of the form Point(x, y) used with operator new creates a new point at the given location, and a method call of the form move(newX, newY) moves a Point to the new location.

With the Point class, let us consider the value assignment $a = new Point(1, 3):

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
                                                           V            V
                                                      [VStore int 1]  [VStore int 3]

Variable $a is given its own VSlot, which points to a VStore that contains a handle pointing to an HStore allocated by new and that is initialized by Point’s constructor.

Now consider the value assignment $b = $a:

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                     ^                     |            |
                                     |                     V            V
[VSlot $b *]-->[VStore object *]-----+             [VStore int 1] [VStore int 3]

$b’s VStore contains a handle that points to the same object as does $a’s VStore’s handle. Note that the Point object itself was not copied, and note that $a’s and $b’s VSlots point to distinct VStores.

Let’s modify the value of the Point whose handle is stored in $b using $b->move(4, 6):

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                     ^                     |            |
                                     |                     V            V
[VSlot $b *]-->[VStore object *]-----+            [VStore int 4] [VStore int 6]
                                       (1 was overwritten) (3 was overwritten)

As we can see, changing $b’s Point changes $a’s as well.

Now, let’s make $a point to a different object using $a = new Point(2, 1):

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
[VSlot $b *]-->[VStore object *]-----+                     V            V
                                     |             [VStore int 2] [VStore int 1]
                                     V
                                   [HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
                                                           V            V
                                                   [VStore int 4] [VStore int 6]

Before $a can take on the handle of the new Point, its handle to the old Point must be removed, which leaves the handles of $a and $b pointing to different Points.

We can remove all these handles using $a = NULL and $b = NULL:

[VSlot $a *]-->[VStore null]    [HStore Point [VSlot $x *] [VSlot $y *] (dead)]
                                                        |            |
[VSlot $b *]-->[VStore null]    [VStore int 2 (dead)]<--+            V
                                                          [VStore int 1 (dead)]

                                [HStore Point [VSlot $x *] [VSlot $y *] (dead)]
                                                        |            |
                                [VStore int 4 (dead)]<--+            V
                                                        [VStore int 6 (dead)]

By assigning null to $a, we remove the only handle to Point(2,1) which makes that object eligible for destruction. A similar thing happens with $b, as it too is the only handle to its Point.

Although the examples above only show with only two instance properties, the same mechanics apply for value assignment of all object types, even though they can have an arbitrarily large number of instance properties of arbitrary type. Likewise, the same mechanics apply to value assignment of all resource types.

ByRef Assignment for Scalar Types with Local Variables

Let’s begin with the same value assignment as in the previous section, $a = 123 and $b = false:

[VSlot $a *]-->[VStore int 123]

[VSlot $b *]-->[VStore bool false]

Now consider the byRef assignment $b =& $a, which has byRef semantics:

[VSlot $a *]-->[VStore int 123]
                 ^
                 |
[VSlot $b *]-----+     [VStore bool false (dead)]

In this example, byRef assignment changes $b’s VSlot point to the same VStore that $a’s VSlot points to. The old VStore that $b’s VSlot used to point to is now unreachable.

When multiple variables’ VSlots point to the same VStore, the variables are said to be aliases of each other or they are said to have an alias relationship. In the example above, after the byRef assignment executes the variables $a and $b will be aliases of each other.

Note that even though in the assignment $b =& $a the variable $b is on the left and $a is on the right, after becoming aliases they are absolutely symmetrical and equal in their relation to the VStore.

When we change the value of $b using ++$b the result is:

[VSlot $a *]-->[VStore int 124 (123 was overwritten)]
                 ^
                 |
[VSlot $b *]-----+

$b’s value, which is stored in the VStore that $b’s VSlot points, is changed to 124. And as that VStore is also aliased by $a’s VSlot, the value of $a is also 124. Indeed, any variable’s VSlot that is aliased to that VStore will have the value 124.

Now consider the value assignment $a = 99:

[VSlot $a *]-->[VStore int 99 (124 was overwritten)]
                 ^
                 |
[VSlot $b *]-----+

The alias relationship between $a and $b can be broken explicitly by using unset on variable $a or variable $b. For example, consider unset($a):

[VSlot $a (dead)]      [VStore int 99]
                         ^
                         |
[VSlot $b *]-------------+

Unsetting $a causes variable $a to be destroyed and its link to the VStore to be removed, leaving $b’s VSlot as the only pointer remaining to the VStore.

Other operations can also break an alias relationship between two or more variables. For example, $a = 123 and $b =& $a, and $c = 'hi':

[VSlot $a *]-->[VStore int 123]
                 ^
                 |
[VSlot $b *]-----+

[VSlot $c *]-->[VStore string 'hi']

After the byRef assignment, $a and $b now have an alias relationship. Next, let’s observe what happens for $b =& $c:

[VSlot $a *]-->[VStore int 123]

[VSlot $b *]-----+
                 |
                 V
[VSlot $c *]-->[VStore string 'hi']

As we can see, the byRef assignment above breaks the alias relationship between $a and $b, and now $b and $c are aliases of each other. When byRef assignment changes a VSlot to point to a different VStore, it breaks any existing alias relationship the left hand side variable had before the assignment operation.

It is also possible to use byRef assignment to make three or more VSlots point to the same VStore. Consider the following example:

$b =& $a;
$c =& $b;
$a = 123;
[VSlot $a *]-->[VStore int 123]
                 ^   ^
                 |   |
[VSlot $b *]-----+   |
                     |
[VSlot $c *]---------+

Like value assignment, byRef assignment provides a means for the programmer to create variables. If the local variables that appear on the left- or right-hand side of byRef assignment do not exist, the engine will bring new local variables into existence and create a VSlot and initial VStore for storing the local variable’s value.

Note that literals, constants, and other expressions that don’t designate a modifiable lvalue cannot be used on the left- or right-hand side of byRef assignment.

ByRef Assignment of Non-Scalar Types with Local Variables

ByRef assignment of non-scalar types works using the same mechanism as byRef assignment for scalar types. Nevertheless, it is worthwhile to describe a few examples to clarify the semantics of byRef assignment. Recall the example using the Point class:

$a = new Point(1, 3);

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
                                                           V            V
                                                  [VStore int 1]  [VStore int 3]

Now consider the byRef assignment $b =& $a, which has byRef semantics:

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *][VSlot $y *]]
                 ^                                         |           |
                 |                                         V           V
[VSlot $b *]-----+                                  [VStore int 1] [VStore int 3]

$a and $b now aliases of each other. Note that byRef assignment produces a different result than $b = $a where $a and $b would point to distinct VStores pointing to the same HStore.

Let’s modify the value of the Point aliased by $a using $a->move(4, 6):

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] VSlot $y *]]
                 ^                                         |           |
                 |                                         V           V
[VSlot $b *]-----+                              [VStore int 4] [VStore int 6]
                                        (1 was overwritten) (3 was overwritten)

Now, let’s change $a itself using the value assignment $a = new Point(2, 1):

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *][VSlot $y *]]
                 ^                                         |           |
                 |                                         V           V
[VSlot $b *]-----+                                [VStore int 2] [VStore int 1]

                               [HStore Point [VSlot $x *]   [VSlot $y *] (dead)]
                                                       |              |
                                                       V              V
                                     [VStore int 4 (dead)] [VStore int 6 (dead)]

As we can see, $b continues to have an alias relationship with $a. Here’s what’s involved in that assignment: $a and $b’s VStore’s handle pointing to Point(4,6) is removed, Point(2,1) is created, and $a and $b’s VStore is overwritten to contain a handle pointing to that new Point. As there are now no VStores pointing to Point(4,6), it can be destroyed.

We can remove these aliases using unset($a, $b):

[VSlot $a (dead)]       [HStore Point [VSlot $x *] [VSlot $y *] (dead)]
                                                |            |
                                                V            V
[VSlot $b (dead)]             [VStore int 2 (dead)]  [VStore int 1 (dead)]

Once all the aliases to the VStores are gone, the VStores can be destroyed, in which case, there are no more pointers to the HStore, and it can be destoyed too.

Value Assignment of Array Types to Local Variables

The semantics of value assignment of array types is different from value assignment of other types. Recall the Point class from the examples, and consider the following value assignments and their abstract implementation:

$a = array(10, 'B' => new Point(1, 3));

[VSlot $a *]-->[VStore array *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]]
                                                         |             |
                                                         V             V
                                               [VStore int 10]   [VStore Obj *]
                                                                             |
                                [HStore Point [VSlot $x *] [VSlot $y *]]<----+
                                                        |            |
                                                        V            V
                                            [VStore int 1]  [VStore int 3]

In the example above, $a’s VStore is initialized to contain a handle to an HStore for an array containing two elements, where one element is an integer and the other is a handle to an HStore for an object.

Now consider the following value assignment $b = $a. A conforming implementation must implement value assignment of arrays in one of the following ways: (1) eager copying, where the implementation makes a copy of $a’s array during value assignment and changes $b’s VSlot to point to the copy; or (2) deferred copying, where the implementation uses a deferred copy mechanism that meets certain requirements. This section describes eager copying, and the section that immediately follows describes deferred copying.

To describe the semantics of eager copying, let’s begin by considering the value assignment $b = $a:

[VSlot $a *]-->[VStore array *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]]
                                                         |             |
[VSlot $b *]-->[VStore array *]                          V             V
                             |                  [VStore int 10]  [VStore object *]
                             V                                                  |
[HStore Array [VSlot 0 *] [VSlot 'B' *]]                                        |
                       |             |                                          |
             +---------+   +---------+                                          |
             V             V                                                    |
[VStore int 10] [VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]<---+
                                                            |            |
                                                            V            V
                                                 [VStore int 1]  [VStore int 3]

The value assignment $b = $a made a copy of $a’s array. Note how $b’s VSlot points to a different VStore than $a’s VSlot, and $b’s VStore points to a different HStore than $a’s VStore. Each source array element is copied using member-copy assignment =*, which is defined as follows:

   $destination =* $source
  • If $source’s VStore has a refcount equal to 1, the Engine copies the array element using value assignment (destination = $source).
  • If $source’s VStore has a refcount that is greater than 1, the Engine uses an implementation-defined algorithm to decide whether to copy the element using value assignment ($destination = $source) or byRef assignment ($destination =& $source).

Note the member-copy assignment =* is not an operator or a language construct in the PHP language, but instead it is used in this text to describe behavior for the engine for array copying and other operations.

For the particular example above, member-copy assignment exhibits the same semantics as value assignment for all conforming implementations because all of the array elements’ VStores have a refcount equal to 1. The first element VSlots in $a’s array and $b’s array point to distinct VStores, each of which contain a distinct copy of the integer value 10. The second element VSlots in $a’s array and $b’s array point to distinct VStores, each of which contain a handle to the same object HStore.

Let’s consider another example:

$x = 123;
$a = array(array(&$x, 'hi'));
$b = $a;

Eager copying can produce two possible outcomes depending on the implementation. Here is the first possible outcome:

[VSlot $a *]---->[VStore array *]---->[HStore Array [VSlot 0 *]]
                                                             |
[VSlot $x *]-------------------------+   [VStore array *]<---+
                                     |                 |
[VSlot $b *]-->[VStore array *]      |                 V
                             |       |  [HStore Array [VSlot 0 *][VSlot 1 *]]
                             V       |                         |          |
         [HStore Array [VSlot 0 *]]  |                         V          |
                                |    +---------------->[VStore int 123]   |
                                V                          ^              V
                     [VStore array *]                      |   [VStore string 'hi']
                                   |        +--------------+
                                   V        |
                     [HStore Array [VSlot 0 *] [VSlot 1 *]]
                                                        |
                                                        V
                                                     [VStore string 'hi']

Here is the second possible outcome:

[VSlot $a *]---->[VStore array *]---->[HStore Array [VSlot 0 *]]
                                                             |
[VSlot $x *]-------------------------+  [VStore array *]<----+
                                     |                |
[VSlot $b *]-->[VStore array *]      |                V
                             |       |  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                             V       |                         |           |
         [HStore Array [VSlot 0 *]]  |                         V           |
                                |    +---------------->[VStore int 123]    |
                                V                                          V
                     [VStore array *]                            [VStore string 'hi']
                                   |
                                   V
                    [HStore Array [VSlot 0 *] [VSlot 1 *]]
                                           |           |
                                           V           V
                                  [VStore int 123]  [VStore string 'hi']

In both possible outcomes, value assignment with eager copying makes a copy of $a’s array, copying the array’s single element using member-copy assignment (which in this case will exhibit the same semantics of value assignment for all implementations), which in turn makes a copy of the inner array inside $a’s array, copying the inner array’s elements using member-copy assignment. The inner array’s first element VSlot points to a VStore that has a refcount that is greater than 1, so an implementation-defined algorithm is used to decide whether to use value assignment or byRef assignment. The first possible outcome shown above demonstrates what happens if the implementation chooses to do byRef assignment, and the second possible outcome shown above demonstrates what happens if the implementation chooses to do value assignment. The inner array’s second element VSlot points to a VStore that has a refcount equal to 1, so value assignment is used to copy the inner array’s second element for all conforming implementations that use eager copying.

Although the examples in this section only use arrays with one element or two elements, the model works equally well for all arrays even though they can have an arbitrarily large number of elements. As to how an HStore accommodates all of them, is unspecified and unimportant to the abstract model.

Deferred Array Copying

As mentioned in the previous section, an implementation may choose to use a deferred copy mechanism instead of eagerly making a copy for value assignment of arrays. An implementation may use any deferred copy mechanism desired so long as it conforms to the abstract model’s description of deferred array copy mechanisms presented in this section.

Because an array’s contents can be arbitrarily large, eagerly copying an array’s entire contents for value assignment can be expensive. In practice an application written in PHP may rely on value assignment of arrays being relatively inexpensive for the common case (in order to deliver acceptable performance), and as such it is common for an implementation to use a deferred array copy mechanism in order to reduce the cost of value assignment for arrays.

Unlike conforming deferred string copy mechanisms discussed before that must produce the same observable behavior as eager string copying, deferred array copy mechanisms are allowed in some cases to exhibit observably different behavior than eager array copying. Thus, for completeness this section describes how deferred array copies can be modeled in the abstract memory model and how conforming deferred array copy mechanisms must behave.

Conforming deferred array copy mechanisms work by not making an array copy during value assignment, by allowing the destination VStore to share an array HStore with the source VStore, and by making a copy of the array HStore at a later time if or when it is necessary. The abstract model represents a deferred array copy relationship by marking the destination VStore with a special “Arr-D” type tag and by sharing the same array HStore between the source and destination VStores. Note that the source VStore’s type tag remains unchanged. For the purposes of this abstract model, the “Arr-D” type tag is considered identical to the array type in all respects except when specified otherwise.

To illustrate this, let’s see how the previous example would be represented under the abstract model assuming the implementation defers the copying the array:

$x = 123;
$a = array(array(&$x, 'hi'));
$b = $a;
[VSlot $a *]--->[VStore array *]--->[HStore Array [VSlot 0 *]]
                                      ^                    |
                                      | [VStore array *]<--+
[VSlot $b *]--->[VStore Arr-D *]------+               |
                                                      V
                                        [HStore Array [VSlot 0 *] [VSlot 1 *]]
                                                               |           |
                                                               V           |
[VSlot $x *]------------------------------------------>[VStore int 123]    |
                                                                           V
                                                               [VStore string 'hi']

As we can see, both $a’s VStore (the source VStore) and $b’s VStore (the destination VStore) point to the same array HStore. Note the asymmetric nature of how deferred array copies are represented in the abstract model. In the above example the source VStore’s type tag remains unchanged after value assignment, whereas the destination VStore’s type tag was changed to “Arr-D”.

When the engine is about to perform an array-mutating operation on a VStore tagged “Arr” that participates in a deferred array copy relationship or on a VStore tagged “Arr-D”, the engine must first take certain actions that involve making a copy of the array (described in the next paragraph) before performing the array-mutating operation. An array-mutating operation is any operation can add or remove array elements, overwrite existing array elements, change the state of the array’s internal cursor, or cause the refcount of one or more of the array’s element VStores or subelement VStores to increase from 1 to a value greater than 1. This requirement to take certain actions before performing an array-mutation operation on a VStore participating in a deferred array copy relationship is commonly referred to as the copy-on-write requirement.

When an array-mutating operation is about to be performed on a given VStore X with an “array” type tag that participates in a deferred array copy relationship, the engine must find all of the VStores tagged “Arr-D” that point to the same array HStore that VStore X points to, make a copy of the array (using member-copy assignment to copy the array’s elements, and update all of these VStores tagged “Arr-D” to point to the newly created copy (note that VStore X remains unchanged). When an array-mutation operation is about to be performed on a given VStore X with an “Arr-D” type tag, the engine must make a copy of the array, update VStore X to point to the newly created copy, and change VStore X’s type tag to “array”. These specific actions that the engine must perform on VStore at certain times to satisfy the copy-on-write requirement are collectively referred to as array-separation or array-separating the VStore. An array-mutation operation is said to trigger an array-separation.

Note that for any VStore with an “array” type tag that participates in a deferred array copy relationship, or for any VStore with an “Arr-D” type tag, a conforming implementation may choose to array-separate the VStore at any time for any reason as long as the copy-on-write requirement is upheld.

Continuing with the previous example, consider the array-mutating operation $b[1]++. Depending on the implementation, this can produce one of three possible outcomes. Here is the one of the possible outcomes:

[VSlot $a *]---->[VStore array *]---->[HStore Array [VSlot 0 *]]
                                                             |
[VSlot $b *]-->[VStore array *]            [VStore Arr *]<---+
                             |                         |
      +----------------------+              +----------+
      V                                     V
  [HStore Array [VSlot 0 *] [VSlot 1 *]]  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                         |           |       ^                   |           |
                         |           V       |                   V           |
                         |   [VStore int 1]  |            [VStore int 123]   |
                         V                   |             ^                 V
                       [VStore Arr-D *]------+             |   [VStore string 'hi']
                                                           |
 [VSlot $x *]----------------------------------------------+

As we can see in the outcome shown above, $b’s VStore was array-separated and now $a’s VStore and $b’s VStore point to distinct array HStores. Performing array-separation on $b’s VStore was necessary to satisfy the copy-on-write requirement. $a’s array remains unchanged and that $x and $a[0][0] still have an alias relationship with each other. For this particular example, conforming implementations are required to preserve $a’s array’s contents and to preserve the alias relationship between $x and $a[0][0]. Finally, note that $a[0] and $b[0] have a deferred copy relationship with each other in the outcome shown above. For this particular example, a conforming implementation is not required to array-separate $b[0]’s VStore, and the outcome shown above demonstrates what happens when $b[0]’s VStore is not array-separated. However, an implementation can choose to array-separate $b[0]’s VStore at any time if desired. The other two possible outcomes shown below demonstrate what can possibly happen if the implementation choose to array-separate $b[0]’s VStore as well. Here is the second possible outcome:

[VSlot $a *]---->[VStore array *]---->[HStore Array [VSlot 0 *]]
                                                             |
[VSlot $b *]-->[VStore array *]          [VStore array *]<---+
                             |                         |
                             V                         V
  [HStore Array [VSlot 0 *] [VSlot 1 *]]  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                         |           |                           |           |
       +-----------------+           V                           |           |
       |                     [VStore int 1]                 +----+           |
       V                                                    |                V
  [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore string 'hi']
                                            |           |   |
                                    +-------+           |   |
                                    |                   V   |
                                    | [VStore string 'hi']  |
                                    V                       |
 [VSlot $x *]--------------------->[VStore int 123]<--------+

Here is the third possible outcome:

[VSlot $a *]---->[VStore array *-]---->[HStore Array [VSlot 0 *]]
                                                              |
[VSlot $b *]-->[VStore array *]           [VStore array *]<---+
                             |                          |
                             V                          V
 [HStore Array [VSlot 0 *] [VSlot 1 *]]  [HStore Array [VSlot 0 *] [VSlot 1 *]]
                        |           |                           |           |
       +----------------+           V                           |           |
       |                     [VStore int 1]                  +--+           |
       V                                                     |              V
   [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore string 'hi']
                                             |           |   |
                     [VStore int 123]<-------+           |   |
                                                         V   |
                                       [VStore string 'hi']  |
                                                             |
 [VSlot $x *]--------------------->[VStore int 123]<---------+

The second and third possible outcomes show what can possibly happen if the implementation chooses to array-separate $b[0]’s VStore. In the second outcome, $b[0][0] has an alias relationship with $x and $a[0][0]. In the third outcome, $b[0][0] does not have an alias relationship, though $x and $a[0][0] still have an alias relationship with each other. The differences between the second and third outcome are reflect that different possibilities when the engine uses member-copy assignment to copy $a[0]’s arrays’s elements into $b[0]’s array.

Finally, let’s briefly consider one more example:

$x = 0;
$a = array(&$x);
$b = $a;
$x = 2;
unset($x);
$b[1]++;
$b[0]++;
echo $a[0], ' ', $b[0];

For the example above, a conforming implementation could output “2 1”, “2 3”, or “3 3” depending on how it implements value assignment for arrays.

For portability, it is generally recommended that programs written in PHP should avoid performing value assignment with a right-hand side that is an array with one or more elements or sub-elements that have an alias relationship.

Implementation Notes: For generality and for simplicity, the abstract model represents deferred array copy mechanisms in a manner that is more open-ended and superficially different than the php.net implementation’s model, which uses a symmetric deferred copy mechanism where a single zval contains the sole pointer to a given Hashtable and deferred array copies are represented as multiple slots pointing to the same single zval that holds the array. Despite this superficial difference, php.net’s implementation produces behavior that is compatible with the abstract model’s definition of deferred array copy mechanisms.

General Value Assignment

The sections above thus far have described the mechanics of value assignment to a local variable. The assignment to a modifiable lvalue that is not a variable, such as array element or object property, works like the local variable assignment, except that the VSlot which represented a variable is replaced by a VSlot that represents the target lvalue. If necessary, such VSlot is created.

For example, assuming Point definition as in previous sections and further assuming all instance properties are public, this code:

$a = new Point(1, 3);
$b = 123;
$a->x = $b;

Will result in:

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
                                                           |            |
                                                           V            V
                                                  [VStore int 123] [VStore int 3]
[VSlot $b *]-->[VStore int 123]

If needed, new VSlots are created as part of the containing VStore, for example:

$a = new Point(1, 3);
$b = 123;
$a->z = $b;

Will result in:

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *] [VSlot $z *]]
                                                           |            |            |
                                                           V            V            V
                                                  [VStore int 1] [VStore int 3] [VStore int 123]
[VSlot $b *]-->[VStore int 123]

The same holds for array elements:

$a = array('hello', 'world');
$b = 'php';
$a[1] = $b;
$a[2] = 'World!';

Will result in:

[VSlot $a *]-->[VStore array *]-->[HStore Array [VSlot 0 *]  [VSlot 1 *]  [VSlot 2 *]]
                                                         |            |            |
                                                         V            V            V
                                    [VStore string 'hello'] [VStore string 'php'] [VStore string 'World!']
[VSlot $b *]-->[VStore string 'php']

Where the third VSlot with index 2 was created by the assignment.

Note that any array element and instance property, including a designation of non-existing ones, is considered a modifiable lvalue, and the VSlot will be created by the engine and added to the appropriate HStore automatically. Static class properties are considered modifiable lvalues too, though new ones would not be created automatically.

General ByRef Assignment

The sections above thus far have described the mechanics of byref assignment with local variables. The byRef assignment to a modifiable lvalue that is not a variable, such as array element or object property, works like the local variable assignment, except that the VSlot which represented a variable is replaced by a VSlot that represents the target lvalue. If necessary, such VSlot is created and added to the corresponding HStore.

For example:

$a = new Point(1, 3);
$b = 123;
$a->z =& $b;

Will result in:

[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *] [VSlot $z *]]
                                                           |            |            |
                                                           V            V            |
                                                  [VStore int 1] [VStore int 3]      |
[VSlot $b *]---------------->[VStore int 123]<---------------------------------------+

Argument Passing

Argument passing is defined in terms of simple assignment or byRef assignment, depending on how the parameter is declared. That is, passing an argument to a function having a corresponding parameter is like assigning that argument to that parameter. The function call situations involving missing arguments or undefined variable arguments are discussed in section describing the function call operator.

Value Returning

Returning a value from a function is defined in terms of simple assignment or byRef assignment, depending on how the function is declared. That is, returning a value from a function to its caller is like assigning that value to the user of the caller’s return value. The function-return situations involving a missing return value are discussed in section describing the function call operator.

Note that to achieve byRef assignment semantics, both function return and assignment of the return value should be byRef. For example:

function &counter()
{
  static $c = 0;
  $c++;
  echo $c." ";
  return $c;
}

$cnt1 = counter();
$cnt1++; // this does not influence counter
$cnt2 =& counter();
$cnt2++; // this does influence counter
counter();

This example prints 1 2 4 , since the first assignment does not produce byRef semantics even though the function return is declared byRef. If the function is not declared to return byRef, its return never produces byRef semantics, regardles of how it is assigned.

Passing function’s return to another function is considered the same as assigning the value to the corresponding function’s parameter, with byRef parameters treated as byRef assignments.

Cloning objects

When an object instance is allocated, operator new returns a handle that points to that object. As described above, value assignment of a handle to an object does not copy the object HStore itself. Instead, it creates a copy of the handle. The copying of the HStore itself is performed via operator clone.

To demonstrate how the clone operator works, consider the case in which an instance of class Widget contains two instance properties: $p1 has the integer value 10, and $p2 is a handle to an array of elements of some type(s) or to an instance of some other type.

[VSlot $a *]-->[VStore object *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]]
                                                             |            |
                                                             V            V
                                               [VStore int 10] [VStore object *]
                                                                              |
                                                        [HStore ...]<---------+

Let us consider the result of $b = clone $a:

[VSlot $a *]-->[VStore object *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]]
                                                             |            |
[VSlot $b *]-->[VStore object *]                             V            V
                             |                  [VStore int 10] [VStore object *]
     +-----------------------+                                                 |
     V                                                                         |
   [HStore Widget [VSlot $p1 *] [VSlot $p2 *]]              +--->[HStore ...]<-+
                             |             |                |
                             V             V                |
                 [VStore int 10] [VStore object *]----------+

The clone operator will create another object HStore of the same class as the original and copy $a’s object’s instance properties using member-copy assignment. For the example shown above, the handle to the newly created HStore stored into $b using value assignment. Note that the clone operator will not recursively clone objects held in $a’s instance properties; hence the object copying performed by the clone operator is often referred to as a shallow copy. If a deep copy of an object is desired, the programmer must achieve this manually by using the method __clone which is called after the initial shallow copy has been performed.

Scope

The same name can designate different things at different places in a program. For each different thing that a name designates, that name is visible only within a part of the program called that name’s scope.

There are a number of scope types that exist in PHP:

  • Variable scope - the scope which defined what unqualified variables (like $foo) are referring to. Variables defined in one variable scope are not visible in another variable scope.
  • Class scope - the scope that defines visibility of the methods and properties, and resolution of keywords like self, parent, etc. Class scope encompasses the body of that class and any classes derived from it.
  • Namespace scope - the scope that defines what unqualified and not-fully-qualified class and function names (e.g. foo() or new Bar()) refer to. Namespace scoping rules are defined in the Namespaces chapter.

For variable scopes, the following scopes can be distinguished:

  • Global scope is the topmost scope of the script, which contains global variables, including pre-defined ones and ones defined outside of any other scope.
  • Function scope, which means from the point of declaration/first initialization through to the end of that function’s body.

Start-up scripts have the global variable scope. Included scripts have the variable scope matching the scope in the place where the inclusion operator was executed.

A variable declared or first initialized inside a function, has function scope; otherwise, the variable has the same variable scope as the enclosing script.

Global variables can be brought into the current scope by using global keyword. Superglobals exist in the global variable scope, however they can be also accessed in any scope; they never need explicit declaration.

Each function has its own function scope. An anonymous function has its own scope separate from that of any function inside which that anonymous function is defined.

The variable scope of a parameter is the body of the function in which the parameter is declared.

The scope of a named-label is the body of the function in which the label is defined.

The class scope of a class member m that is declared in, or inherited by, a class type C is the body of C.

The class scope of an interface member m that is declared in, or inherited by, an interface type I is the body of I.

When a trait is used by a class or an interface, the trait’s members take on the class scope of a member of that class or interface.

Storage Duration

The lifetime of a variable is the time during program execution that storage for that variable is guaranteed to exist. This lifetime is referred to as the variable’s storage duration, of which there are three kinds: automatic, static, and allocated.

A variable having automatic storage duration comes into being and is initialized at its declaration or on its first use, if it has no declaration. Its lifetime is delimited by an enclosing scope. The automatic variable’s lifetime ends at the end of that scope. Automatic variables lend themselves to being stored on a stack where they can help support argument passing and recursion. Local variables, which include function parameters, have automatic storage duration.

A variable having static storage duration comes into being and is initialized before its first use, and lives until program shutdown. The following kinds of variables have static storage duration: constants, function statics, global variables, static properties, and class and interface constants.

A variable having allocated storage duration comes into being based on program logic by use of the new operator or a factory function. Ordinarily, once such storage is no longer needed, it is reclaimed automatically by the Engine via its garbage-collection process and the use of destructors. The following kinds of variables have allocated storage duration: array elements and instance properties.

Although all three storage durations have default ends-of-life, their lives can be shortened by using the unset statement, which destroys any given set of variables.

The following example demonstrates the three storage durations:

class Point { ... }

$av1 = new Point(0, 1);       // auto variable $av1 created and initialized
static $sv1 = ...;          // static variable $sv1 created and initialized

function doit($p1)
{
  $av2 = ...;           // auto variable $av2 created and initialized
  static $sv2 = ...;        // static variable $sv2 created and initialized
  if ($p1)
  {
    $av3 = ...;         // auto variable $av3 created and initialized
    static $sv3 = ...;    // static variable $sv3 created and initialized
    ...
  }
  global $av1;
  $av1 = new Point(2, 3);   // Point(0,1) is eligible for destruction
  ...
}                   // $av2 and $av3 are eligible for destruction

doit(TRUE);

// At end of script, $av1, $sv1, $sv2, and $sv3 are eligible for destruction

The comments indicate the beginning and end of lifetimes for each variable. In the case of the initial allocated Point variable whose handle is stored in $av1, its life ends when $av1 is made to point to a different Point.

If function doit is called multiple times, each time it is called, its automatic variables are created and initialized, whereas its static variables retain their values from previous calls.

Consider the following recursive function:

function factorial($i)
{
  if ($i > 1) return $i * factorial($i - 1);
  else if ($i == 1) return $i;
  else return 0;
}

When factorial is first called, the local variable parameter $i is created and initialized with the value of the argument in the call. Then, if this function calls itself, the same process is repeated each call. Specifically, each time factorial calls itself, a new local variable parameter $i is created and initialized with the value of the argument in the call.

The lifetime of any VStore or HStore can be extended by the Engine as long as needed. Conceptually, the lifetime of a VStore ends when it is no longer pointed to by any VSlots. Conceptually, the lifetime of an HStore ends when no VStores have a handle to it.

Types

General

The meaning of a value is determined by its type. PHP’s types are categorized as scalar types and composite types. The scalar types are Boolean, integer, floating point, string, and null. The composite types are array, and object. The resource is an opaque type whose internal structure is not specified and depends on the implementation.

The scalar types are value types. That is, a variable of scalar type behaves as though it contains its own value.

The composite types can contain other variables, besides the variable itself, e.g. array contains its elements and object contains its properties.

The objects and resources are handle types. The type contains information — in a handle — that leads to the value. The differences between value and handle types become apparent when it comes to understanding the semantics of assignment, and passing arguments to, and returning values from, functions.

Variables are not declared to have a particular type. Instead, a variable’s type is determined at runtime by the value it contains. The same variable can contain values of different types at different times.

Useful library functions for interrogating and using type information include gettype, is_type, settype, and var_dump.

Scalar Types

General

The integer and floating-point types are collectively known as arithmetic types. The library function is_numeric indicates if a given value is a number or a numeric string.

The library function is_scalar indicates if a given value has a scalar type. However, that function does not consider NULL to be scalar. To test for NULL, use is_null.

Some objects may support arithmetic and other scalar operations and/or be convertible to scalar types (this is currently available only to internal classes). Such object types together with scalar types are called scalar-compatible types. Note that the same object type may be scalar-compatible for one operation but not for another.

The Boolean Type

The Boolean type is bool, for which the name boolean is a synonym. This type is capable of storing two distinct values, which correspond to the Boolean values true and false, respectively. The internal representation of this type and its values is unspecified.

The library function is_bool indicates if a given value has type bool.

The Integer Type

There is one integer type, int, for which the name integer is a synonym. This type is binary, signed, and uses twos-complement representation for negative values. The range of values that can be stored is implementation-defined; however, the range [-2147483648, 2147483647], must be supported. This range must be finite.

Certain operations on integer values produce a mathematical result that cannot be represented as an integer. Examples include the following:

  • Incrementing the largest value or decrementing the smallest value.
  • Applying the unary minus to the smallest value.
  • Multiplying, adding, or subtracting two values.

In such cases, the computation is done as though the types of the values were float with the result having that type.

The constants PHP_INT_SIZE, PHP_INT_MIN and PHP_INT_MAX define certain characteristics about type int.

The library function is_int indicates if a given value has type int.

The Floating-Point Type

There is one floating-point type, float, for which the names double and real are synonyms. The float type must support at least the range and precision of IEEE 754 64-bit double-precision representation.

The library function is_float indicates if a given value has type float. The library function is_finite indicates if a given floating-point value is finite. The library function is_infinite indicates if a given floating-point value is infinite. The library function is_nan indicates if a given floating-point value is a NaN.

The String Type

A string is a set of contiguous bytes that represents a sequence of zero or more characters.

Conceptually, a string can be considered as an array of bytes—the elements—whose keys are the int values starting at zero. The type of each element is string. However, a string is not considered a collection, so it cannot be iterated over.

A string whose length is zero is an empty string.

As to how the bytes in a string translate into characters is unspecified.

Although a user of a string might choose to ascribe special semantics to bytes having the value \0, from PHP’s perspective, such null bytes have no special meaning. PHP does not assume strings contain any specific data or assign special values to any bytes or sequences. However, many library functions assume the strings they receive as arguments are UTF-8 encoded, often without explicitly mentioning that fact.

A numeric string is a string whose content exactly matches the pattern defined by the str-numeric production below. A leading-numeric string is a string whose initial characters follow the requirements of a numeric string, and whose trailing characters are non-numeric. A non-numeric string is a string that is not a numeric string.

str-numeric::
   str-whitespaceopt   signopt   str-number

str-whitespace::
   str-whitespaceopt   str-whitespace-char

str-whitespace-char::
   new-line
   Space character (0x20)
   Horizontal-tab character (0x09)
   Vertical-tab character (0x0B)
   Form-feed character (0x0C)

str-number::
   digit-sequence
   floating-literal

Note that digit-sequence is interpreted as having base-10 (so "0377" is treated as 377 decimal with a redundant leading zero, rather than as octal 377).

Only one mutation operation may be performed on a string, offset assignment, which involves the simple assignment operator =.

The library function is_string indicates if a given value has type string.

The Null Type

The null type has only one possible value, NULL. The representation of this type and its value is unspecified.

The library function is_null indicates if a given value is NULL.

Composite Types

The Array Type

An array is a data structure that contains a collection of zero or more elements whose values are accessed through keys that are of type int or string. See more details in arrays chapter.

The library function is_array indicates if a given value is an array.

Objects

An object is an instance of a class. Each distinct class-declaration defines a new class type, and each class type is an object type. The representation of object types is unspecified.

The library function is_object indicates if a given value is an object, and the library function get_class indicates the name of an object’s class.

Resources

A resource is a descriptor to some sort of external entity. Examples include files, databases, and network sockets.

A resource is an abstract entity whose representation is unspecified. Resources are only created or consumed by the implementation; they are never created or consumed by PHP code.

Each distinct resource has a unique identity of some unspecified form.

The library function is_resource indicates if a given value is a resource, and the library function get_resource_type indicates the type of a resource.

Constants

General

A constant is a named value. Once defined, the value of the constant can not be changed.

A constant can be defined in one of two ways: as a c-constant using a const-declaration, or as a d-constant by calling the library function define. However, the two approaches differ slightly. Specifically:

  • The name of a c-constant must comply with the lexical grammar for a name while that for a d-constant can contain any source character.
  • If define is able to define the given name, it returns TRUE; otherwise, it returns FALSE.

The constants can only hold a value of a scalar type, an array or a resource.

The library function defined reports if a given name (specified as a string) is defined as a constant. The library function constant returns the value of a given constant whose name is specified as a string.

Examples

const MAX_HEIGHT = 10.5;              // define two (case-sensitive) c-constants
const UPPER_LIMIT = MAX_HEIGHT;
define('COEFFICIENT_1', 2.345, TRUE); // define a case-insensitive d-constant (deprecated)
define('FAILURE', FALSE, FALSE);      // define a case-sensitive d-constant

Context-Dependent Constants

The following constants—sometimes referred to as magic constants—are automatically available to all scripts; their values are not fixed and they are case-insensitive:

Constant NameDescription
__CLASS__string; The name of the current class. From within a trait method, the name of the class in which that trait is used. If the current namespace is other than the default, the namespace name and \ are prepended, in that order. If used outside all classes, the value is the empty string.
__COMPILER_HALT_OFFSET__int; When the __halt_compiler(); construct is used, this constant contains the byte offset in the source file immediately following the __halt_compiler(); token in this file.
__DIR__string; The directory name of the script. A directory separator is only appended for the root directory.
__FILE__string; The full name of the script.
__FUNCTION__string; Inside a function, the name of the current function exactly as it was declared, with the following prepended: If a named namespace exists, that namespace name followed by “". If used outside all functions, the result is the empty string. For a method, no parent-class prefix is present. (See __METHOD__ and anonymous functions).
__LINE__int; the number of the current source line.
__METHOD__string; Inside a method, the name of the current method exactly as it was declared, with the following prepended, in order: If a named namespace exists, that namespace name followed by \; the parent class name or trait name followed by ::. If used outside all methods, the result is the same as for __FUNCTION__.
__NAMESPACE__string; The name of the current namespace exactly as it was declared. For the default namespace, the result is the empty string.
__TRAIT__string; The name of the current trait. From within a trait method, the name of the current trait. If used outside all traits, the result is the empty string.

Constant names beginning with __ are reserved for future use by the Engine.

Core Predefined Constants

The following constants are automatically available to all scripts; they are case-sensitive with the exception of NULL, TRUE and FALSE:

Constant NameDescription
DEFAULT_INCLUDE_PATHstring; the fopen library function include path is used if it is not overridden by the php.ini setting include_path.
E_ALLint; All errors and warnings, as supported.
E_COMPILE_ERRORint; Fatal compile-time errors. This is like an E_ERROR, except that E_COMPILE_ERROR is generated by the scripting engine.
E_COMPILE_WARNINGint; Compile-time warnings (non-fatal errors). This is like an E_WARNING, except that E_COMPILE_WARNING is generated by the scripting engine.
E_CORE_ERRORint; Fatal errors that occur during PHP’s initial start-up. This is like an E_ERROR, except that E_CORE_ERROR is generated by the core of PHP.
E_CORE_WARNINGint; Warnings (non-fatal errors) that occur during PHP’s initial start-up. This is like an E_WARNING, except that E_CORE_WARNING is generated by the core of PHP.
E_DEPRECATEDint; Deprecation notices. Enable this to receive warnings about code that will not work in future versions.
E_ERRORint; Fatal run-time errors. These indicate errors that cannot be recovered from, such as a memory allocation problem. Execution of the script is halted.
E_NOTICEint; Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.
E_PARSEint; Compile-time parse errors.
E_RECOVERABLE_ERRORint; Catchable fatal error. It indicates that a probably dangerous error occurred, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handler (see the library function set_error_handler), the application aborts as it was an E_ERROR.
E_STRICTint; Have PHP suggest changes to the source code to ensure the best interoperability.
E_USER_DEPRECATEDint; User-generated error message. This is like an E_DEPRECATED, except that E_USER_DEPRECATED is generated in PHP code by using the library function trigger_error.
E_USER_ERRORint; User-generated error message. This is like an E_ERROR, except that E_USER_ERROR is generated in PHP code by using the library function trigger_error.
E_USER_NOTICEint; User-generated warning message. This is like an E_NOTICE, except that E_USER_NOTICE is generated in PHP code by using the library function trigger_error.
E_USER_WARNINGint; User-generated warning message. This is like an E_WARNING, except that E_USER_WARNING is generated in PHP code by using the library function trigger_error.
E_WARNINGint; Run-time warnings (non-fatal errors). Execution of the script is not halted.
FALSEbool; the case-insensitive Boolean value FALSE.
INFfloat; Infinity
M_1_PIfloat; 1/pi
M_2_PIfloat; 2/pi
M_2_SQRTPIfloat; 2/sqrt(pi)
M_Efloat; e
M_EULERfloat; Euler constant
M_LN10float; log_e 10
M_LN2float; log_e 2
M_LNPIfloat; log_e(pi)
M_LOG10Efloat; log_10 e
M_LOG2Efloat; log_2 e
M_PIfloat; Pi
M_PI_2float; pi/2
M_PI_4float; pi/4
M_SQRT1_2float; 1/sqrt(2)
M_SQRT2float; sqrt(2)
M_SQRT3float; sqrt(3)
M_SQRTPIfloat; sqrt(pi)
NANfloat; Not-a-Number
NULLnull; the case-insensitive value NULL.
PHP_BINARYstring; the PHP binary path during script execution.
PHP_BINDIRstring; the installation location of the binaries.
PHP_CONFIG_FILE_PATHstring; location from which php.ini values were parsed
PHP_CONFIG_FILE_SCAN_DIRstring; The directory containing multiple INI files, all of which were parsed on start-up.
PHP_DEBUGint; Indicates whether the engine was built with debugging enabled.
PHP_EOLstring; the end-of-line terminator for this platform.
PHP_EXTENSION_DIRstring; The directory to be searched by the library function dl when looking for runtime extensions.
PHP_EXTRA_VERSIONstring; the current PHP extra version.
PHP_INT_MAXint; the maximum representable value for an integer.
PHP_INT_MINint; the minimum representable value for an integer.
PHP_INT_SIZEint; the number of bytes used to represent an integer.
PHP_FLOAT_DIGint; the number of decimal digits that can be rounded into a float and back without precision loss.
PHP_FLOAT_EPSILONfloat; the smallest representable positive number x, so that x + 1.0 != 1.0.
PHP_FLOAT_MINfloat; the smallest representable normalized floating point number larger than zero.
PHP_FLOAT_MAXfloat; the largest representable floating point number.
PHP_MAJOR_VERSIONint; the current PHP major version
PHP_MANDIRstring; the installation location of the manual pages.
PHP_MAXPATHLENint; the maximum length of a fully qualified filename supported by this build.
PHP_MINOR_VERSIONint; the current PHP minor version.
PHP_OSstring; the current operating system.
PHP_OS_FAMILYstring; the operating system family PHP was built for. Either of ‘Windows’, ‘BSD’, ‘Darwin’, ‘Solaris’, ‘Linux’ or ‘Unknown’.
PHP_PREFIXstring; the value to which “–prefix” was set when configured.
PHP_RELEASE_VERSIONint; the current PHP release version.
PHP_ROUND_HALF_DOWNint; Round halves down.
PHP_ROUND_HALF_EVENint; Round halves to even numbers.
PHP_ROUND_HALF_ODDint; Round halves to odd numbers.
PHP_ROUND_HALF_UPint; Round halves up.
PHP_SAPIstring; the Server API for this build.
PHP_SHLIB_SUFFIXstring; build-platform’s shared library suffix.
PHP_SYSCONFDIRstring; the PHP system configuration directory.
PHP_VERSIONstring; the current PHP version in the form “major.minor.release[extra]”.
PHP_VERSION_IDint; the current PHP version.
PHP_ZTSint; Indicates whether the compiler was built with thread safety enabled.
STDINresource; File resource that maps to standard input (php://stdin).
STDOUTresource; File resource that maps to standard output (php://stdout).
STDERRresource; File resource that maps to standard error (php://stderr).
TRUEbool; the case-insensitive Boolean value TRUE.

The members of the E_* family have values that are powers of 2, so they can be combined meaningfully using bitwise operators.

User-Defined Constants

A constant may be defined inside or outside of functions, inside a class, or inside an interface.

Variables

General

A variable is a named area of data storage that contains a PHP value. A variable is represented by a VSlot. A variable is created by assigning a value to it. A variable is destroyed by unsetting it, either by an explicit call to the unset statement, or by the Engine. The intrinsic isset tests if a given variable exists and is not set to NULL. If a variable, which is not defined so far, is used in an expression, then different strategies are applied which determine whether the variable is defined implicitly or a substitution value is used instead and whether a notice is emitted or not. The strategies depend on the kind of the variable as well as on the context where the undefined variable is being used. The strategies are elaborated in the sub-sections of the different kinds of variables below.

Variables have names. Distinct variables may have the same name provided they are in different scopes.

A constant is a variable that, once initialized, its value cannot be changed.

Based on the context in which it is declared, a variable has a scope and a storage duration.

A superglobal variable is a global variable that is accessible in all scopes without the need for a global-declaration.

The following kinds of variable may exist in a script:

Kinds of Variables

Constants

Syntax

See constants section.

Constraints

Outside of a class or interface, a c-constant can be defined only at the top level of a script.

Semantics

See constants and class constants.

A constant defined outside of a class or interface is a superglobal. A constant has static storage duration and is a non-modifiable lvalue.

Undefined Constants

Undefined constants are not defined implicitly – forward usages of constants are also classified as undefined constants here. A distinction between class/interface constants and top level constants is made.

For top level constants: For unqualified usages, the name of the undefined constant (as string) is used as substitution value. Moreover, a warning is emitted stating that the corresponding constant was undefined. For qualified usages, an exception of type Error is thrown.

For class/interface constants: An exception of type Error is thrown, stating that the corresponding constant was undefined.

Examples

const MAX_HEIGHT = 10.5;        // define two c-constants
const UPPER_LIMIT = MAX_HEIGHT;
define('COEFFICIENT_1', 2.345); // define two d-constants
define('FAILURE', TRUE);

// Examples of undefined constants
echo NON_EXISTING_CONSTANT;     // uses 'NON_EXISTING_CONSTANT' as substitution
                                // value and emits a warning stating that the
                                // constant was undefined.

echo NON_EXISTING_CONSTANT;     // same here, the constant is still undefined
                                // and 'NON_EXISTING_CONSTANT' is used as
                                // substitution value and a warning is emitted
                                // again.

echo MAX_LENGTH;                // same here due to a forward usage
                                // (MAX_LENGTH is defined further below).
                                // 'MAX_LENGTH' is used as substitution
                                // value and a warning is emitted.

echo \NON_EXISTING_CONSTANT;    // qualified use of undefined constant. Throws
                                // an exception of type Error.

const MAX_LENGTH = 7.5;

echo Exception::MESSAGE;        // undefined class constant. Throws an exception
                                // of type Error.

Local Variables

Syntax

See Semantics below.

Semantics

Except for a parameter, a local variable is never defined explicitly; instead, it is created when it is first assigned a value. A local variable can be assigned to as a parameter in the parameter list of a function definition or inside any compound statement. It has function scope and automatic storage duration. A local variable is a modifiable lvalue.

Examples

function doit($p1)  // assigned the value TRUE when called
{
  $count = 10;
    ...
  if ($p1)
  {
    $message = "Can't open master file.";
    ...
  }
  ...
}
doit(TRUE);
// -----------------------------------------
function f()
{
  $lv = 1;
  echo "\$lv = $lv\n";
  ++$lv;
}
for ($i = 1; $i <= 3; ++$i)
  f();

Unlike the function static equivalent, function f outputs “$lv = 1” each time.

See the recursive function example in storage duration section.

Undefined Local Variables

A distinction is made based on the context where an undefined local variable is used.

byVal Context

PHP does not implicitly define an undefined local variable and uses NULL as substitution value instead. Furthermore, a notice is emitted, stating that the corresponding variable was undefined, unless the variable is used

  1. as the single expression in a statement.
  2. as argument of isset.
  3. as argument of empty.
  4. as the left hand side of the coalesce operator ??.

Since undefined local variables are not defined implicitly, they stay undefined. In general, a VSlot is not created for undefined variables used in a byValue context.

byRef Context

If the undefined variable is used in a byRef context then PHP defines the variable implicitly. Hence, a VSlot is created for it and NULL is stored in it. A notice is not emitted in such a case.

Examples of Undefined Variables

Following some examples which outlines the behaviour with undefined local variables.

// The following 4 cases outline the exceptions of undefined variables
// used in byValue context where no notice is emitted.
$a;
isset($a);
empty($a);
$a ?? 'default Value';

$a = 1;    // a VSlot for $a was created and 1 was assigned.

$b = $c;   // a VSlot for $b was created and the value of $c was assigned to
           // it. But because $c in turn was undefined, NULL was used as
           // substitution value instead. In addition, a notice was
           // emitted stating that $c was undefined.

$d = $c;   // a VSlot for $d was created and the value of $c was assigned to
           // it. But since $c is still undefined, NULL was used as
           // substitution value instead and another notice was emitted
           // stating $c was undefined.

$d + $e;   // $e was undefined and `NULL` was used as substitution value
           // instead. In addition, a notice was emitted stating that
           // $e was undefined.

$f = &$g;  // a VSlot for $f was created which points to the VSlot of $g.
           // $g in turn was undefined but was defined implicitly because the
           // assignment was byRef. Thus a VSlot for $g was created and `NULL`
           // was assigned to it. A notice was *not* emitted.

$h = $g;   // a VSlot for $h was created and the value of $g (which is NULL)
           // was assigned to it.

function foo($x){}

foo($i);   // $i was undefined and NULL was used as substitution value
           // instead. In addition, a notice was emitted stating that $i
           // was undefined.

$j = $i;   // a VSlot for $j was created and the value of $i was assigned to
           // it. But because $i in turn was still undefined, NULL was used
           // as substitution value instead. Another notice was emitted
           // stating that $i was undefined.

function bar(&$x){}

bar($k);   // $k was undefined but implicitly defined because it was passed to
           // the function bar byRef. Thus a VSlot for $k was created and
           // NULL was assigned to it. A notice was *not* emitted.

$l = $k;   // a VSlot for $l was created and the value of $k (which is NULL)
           // was assigned to it.

Array Elements

Syntax

Arrays are created using the array-creation operator. At the same time, one or more elements may be created for that array. New elements are inserted into an existing array via the simple-assignment operator in conjunction with the subscript operator []. Elements can be removed by calling the unset statement.

Semantics

The scope of an array element is the same as the scope of that array’s name. An array element has allocated storage duration.

Undefined Array Elements

Similar to undefined local variables, a distinction is made based on the context where an undefined array element is used.

byValue Context

If one tries to access an undefined array element, then NULL is used as substitution value and a notice is emitted, stating that an undefined offset was used. The undefined offset is not created implicitly and a subsequent access results in another notice.

byRef Context

PHP defines implicitly an undefined array element when it is accessed byRef, a VSlot for the corresponding undefined offset is created and NULL is assigned to it. A notice is not emitted in this case.

Examples

$colors = ["red", "white", "blue"]; // create array with 3 elements
$colors[] = "green";                // insert a new element

echo $colors[100];      // element with offset 100 is undefined and NULL is
                        // used as substitution value. Moreover, a notice is
                        // emitted stating that an undefined offset was used.

echo $colors[100];      // element with offset 100 is still undefined and NULL
                        // is used as substitution value instead. Another
                        // notice is emitted.

$b = &$colors[100];     // a VSlot for $b is created which points to the array
                        // element with the offset 100. An array element with
                        // offset 100 was undefined but implicitly defined
                        // because the assignment is byRef. Thus a VSlot for
                        // the array element with offset 100 is created and
                        // NULL is assigned to it. A notice is *not* emitted.

Function Statics

Syntax

function-static-declaration:
   static   static-variable-name-list   ;

static-variable-name-list:
   static-variable-declaration
   static-variable-name-list   ,   static-variable-declaration

static-variable-declaration:
   variable-name   function-static-initializeropt

function-static-initializer:
   =   constant-expression

Constraints

A function static must be defined inside a function.

Semantics

A function static may be defined inside any compound statement. It is a modifiable lvalue.

A function static has function scope and static storage duration.

The value of a function static is retained across calls to its parent function. Each time the function containing a function static declaration is called, that execution is dealing with an alias to that static variable. If that alias is passed to the unset statement, only that alias is destroyed. The next time that function is called, a new alias is created.

Undefined Function Statics

Function statics are explicitly defined and thus cannot be undefined.

Examples

function f()
{
  static $fs = 1;
  echo "\$fs = $fs\n";
  ++$fs;
}
for ($i = 1; $i <= 3; ++$i)
  f();

Unlike the local variable equivalent, function f outputs “$fs = 1”, “$fs = 2”, and “$fs = 3”, as $fs retains its value across calls.

Be also aware that declaring a function static can hide a local variable and/or a global variable with the same name. The value of the local or global variable is not taken over as initial value of the function static. Subsequent modifications of the variable only modify the function static and do not affect the local nor the global variable. An example:

function f(){
  $fs = 10;             // assign 10 to the local variable $fs
  static $fs;           // define a function static with name $fs
  echo "\$fs = $fs\n";  // $fs =
  $fs = 5;              // assign 5 to the function static $fs (local variable is not modified)
  echo "\$fs = $fs\n";  // $fs = 5
  global $fs;           // define a global variable with name $fs
  echo "\$fs = $fs\n";  // $fs =
  $fs = 3;              // assign 3 to the global variable $fs (function static and local variable is not modified
  echo "\$fs = $fs\n";  // $fs = 3
  static $fs;
  ++$fs;                // increment function static $fs
  echo "\$fs = $fs\n";  // $fs = 6
}
f();
echo "\$fs = $fs\n";    // $fs = 3

Global Variables

Syntax

global-declaration:
   global   variable-name-list   ;

variable-name-list:
   simple-variable
   variable-name-list   ,   simple-variable

Semantics

A global variable is never defined explicitly; instead, it is created when it is first assigned a value. That may be done at the top level of a script, or from within a block in which that variable has been declared (imported, that is) using the global keyword.

One of the predefined variables, $GLOBALS is a superglobal array whose elements’ key/value pairs contain the name and value, respectively, of each global variable currently defined. As such, a global variable gv can be initialized with the value v, and possibly be created, using the following form of assignment:

$GLOBALS['gv'] = v

As $GLOBALS is a superglobal, gv need not first be the subject of a global-declaration.

A global variable has global scope and static storage duration. A global variable is a modifiable lvalue.

When a global value is imported into a function, each time the function is called, that execution is dealing with an alias to that global variable. If that alias is passed to the unset statement, only that alias is destroyed. The next time that function is called, a new alias is created with the current value of the global variable.

Undefined Global Variables

The same rules as for undefined local variables apply.

Examples

$colors = array("red", "white", "blue");
$GLOBALS['done'] = FALSE;
// -----------------------------------------
$min = 10; $max = 100; $average = NULL;
global $min, $max;         // allowed, but serves no purpose
function compute($p)
{
  global $min, $max;
  global $average;
  $average = ($max + $min)/2;

  if ($p)
  {
    global $result;
    $result = 3.456;  // initializes a global, creating it, if necessary
  }
}
compute(TRUE);
echo "\$average = $average\n";  // $average = 55
echo "\$result = $result\n";  // $result = 3.456
// -----------------------------------------
$g = 100;
function f()
{
  $v = 'g';
  global $$v;          // import global $g
  ...
}

Be also aware that declaring a variable global can hide a local variable and/or a function static with the same name. See static variables section for an example.

Instance Properties

These are described in class instance properties section. They have class scope of the defining class and allocated storage duration. Access to the instance properties is governed by visibility rules.

Static Properties

These are described in class static properties section. They have class scope of the defining class and static storage duration. Access to the static properties is governed by visibility rules.

Class and Interface Constants

These are described in class constants section and interface constants section. They have class scope of the defining class or interface and static storage duration.

Predefined Variables

The following global variables are available to all scripts:

Variable NameDescription
$argcint; The number of command-line arguments passed to the script. This is at least 1. (See $argv below). This may not be available in non-command-line builds of the Engine.
$argvarray; An array of $argc elements containing the command-line arguments passed to the script as strings. Each element has an int key with the keys being numbered sequentially starting at zero through $argc-1. $argv[0] is the name of the script. It is implementation-defined as to how white space on command lines is handled, whether letter casing is preserved, which characters constitute quotes, or how $argv[0]’s string is formatted. As to how command-line arguments are defined, is unspecified. This may not be available in non-command-line builds of the Engine.
$_COOKIEarray; The variables passed to the current script via HTTP Cookies.
$_ENVarray; An array in which the environment variable names are element keys, and the environment variable value strings are element values. As to how an environment variable is defined, is unspecified.
$_FILESarray; The items uploaded to the current script via the HTTP POST method.
$_GETarray; The variables passed to the current script via the URL parameters.
$GLOBALSarray; A superglobal array containing the names of all variables that are currently defined in the global scope of the script. The variable names are the element keys, and the variable values are the element values.
$_POSTarray; The variables passed to the current script via the HTTP POST method.
$_REQUESTarray; By default contains the contents of $_COOKIE, $_GET, and $_POST. The exact contents may depend on the Engine settings.
$_SERVERarray; Server and execution environment information, such as headers, paths, and script locations. The entries in this array are taken from the Engine environment, e.g. the webserver.
$_SESSIONarray; The session variables available to the current script. This global is defined only if a session is active.

All $_* variables above are superglobals. The exact set of the variables available may depend on the implementation, the Engine build and the environment.

Conversions

General

Explicit type conversion is performed using the cast operator. If an operation or language construct expects operand of one type and a value of another type is given, implicit (automatic) conversion will be performed. Same will happen with most internal functions, though some functions may do different things depending on argument type and thus would not perform the conversion.

If an expression is converted to its own type, the type and value of the result are the same as the type and value of the expression.

Conversions to resource and null types can not be performed.

Converting to Boolean Type

The result type is bool.

If the source type is int or float, then if the source value tests equal to 0, the result value is FALSE; otherwise, the result value is TRUE.

If the source value is NULL, the result value is FALSE.

If the source is an empty string or the string “0”, the result value is FALSE; otherwise, the result value is TRUE.

If the source is an array with zero elements, the result value is FALSE; otherwise, the result value is TRUE.

If the source is an object, the result value is TRUE.

If the source is a resource, the result value is TRUE.

The library function boolval allows values to be converted to bool.

Converting to Integer Type

The result type is int.

If the source type is bool, then if the source value is FALSE, the result value is 0; otherwise, the result value is 1.

If the source type is float, for the values INF, -INF, and NAN, the result value is zero. For all other values, if the precision can be preserved (that is, the float is within the range of an integer), the fractional part is rounded towards zero. If the precision cannot be preserved, the following conversion algorithm is used, where X is defined as two to the power of the number of bits in an integer (for example, 2 to the power of 32, i.e. 4294967296):

  1. We take the floating point remainder (wherein the remainder has the same sign as the dividend) of dividing the float by X, rounded towards zero.
  2. If the remainder is less than zero, it is rounded towards infinity and X is added.
  3. This result is converted to an unsigned integer.
  4. This result is converted to a signed integer by treating the unsigned integer as a two’s complement representation of the signed integer.

Implementations may implement this conversion differently (for example, on some architectures there may be hardware support for this specific conversion mode) so long as the result is the same.

If the source value is NULL, the result value is 0.

If the source is a numeric string or leading-numeric string having integer format, if the precision can be preserved the result value is that string’s integer value; otherwise, the result is undefined. If the source is a numeric string or leading-numeric string having floating-point format, the string’s floating-point value is treated as described above for a conversion from float. The trailing non-numeric characters in leading-numeric strings are ignored. For any other string, the result value is 0.

If the source is an array with zero elements, the result value is 0; otherwise, the result value is 1.

If the source is an object, if the class defines a conversion function, the result is determined by that function (this is currently available only to internal classes). If not, the conversion is invalid, the result is assumed to be 1 and a non-fatal error is produced.

If the source is a resource, the result is the resource’s unique ID.

The library function intval allows values to be converted to int.

Converting to Floating-Point Type

The result type is float.

If the source type is int, if the precision can be preserved the result value is the closest approximation to the source value; otherwise, the result is undefined.

If the source is a numeric string or leading-numeric string having integer format, the string’s integer value is treated as described above for a conversion from int. If the source is a numeric string or leading-numeric string having floating-point format, the result value is the closest approximation to the string’s floating-point value. The trailing non-numeric characters in leading-numeric strings are ignored. For any other string, the result value is 0.

If the source is an object, if the class defines a conversion function, the result is determined by that function (this is currently available only to internal classes). If not, the conversion is invalid, the result is assumed to be 1.0 and a non-fatal error is produced.

For sources of all other types, the conversion result is obtained by first converting the source value to int and then to float.

The library function floatval allows values to be converted to float.

Converting to String Type

The result type is string.

If the source type is bool, then if the source value is FALSE, the result value is the empty string; otherwise, the result value is “1”.

If the source type is int or float, then the result value is a string containing the textual representation of the source value (as specified by the library function sprintf).

If the source value is NULL, the result value is the empty string.

If the source is an array, the conversion is invalid. The result value is the string “Array” and a non-fatal error is produced.

If the source is an object, then if that object’s class has a __toString method, the result value is the string returned by that method; otherwise, the conversion is invalid and a fatal error is produced.

If the source is a resource, the result value is an implementation-defined string.

The library function strval allows values to be converted to string.

Converting to Array Type

The result type is array.

If the source value is NULL, the result value is an array of zero elements.

If the source type is scalar or resource and it is non-NULL, the result value is an array of one element under the key 0 whose value is that of the source.

If the source is an object, the result is an array of zero or more elements, where the elements are key/value pairs corresponding to the object’s instance properties. The order of insertion of the elements into the array is the lexical order of the instance properties in the class-member-declarations list.

For public instance properties, the keys of the array elements would be the same as the property name.

The key for a private instance property has the form “\0class\0name”, where the class is the class name, and the name is the property name.

The key for a protected instance property has the form “\0*\0name”, where name is that of the property.

The value for each key is that from the corresponding property, or NULL if the property was not initialized.

Converting to Object Type

The result type is object.

If the source has any type other than object, the result is an instance of the predefined class stdClass. If the value of the source is NULL, the instance is empty. If the value of the source has a scalar type and is non-NULL, or is a resource, the instance contains a public property called scalar whose value is that of the source. If the value of the source is an array, the instance contains a set of public properties whose names and values are those of the corresponding key/value pairs in the source. The order of the properties is the order of insertion of the source’s elements.

Lexical Structure

Scripts

A script is an ordered sequence of characters. Typically, a script has a one-to-one correspondence with a file in a file system, but this correspondence is not required. PHP scripts are parsed as a series of 8-bit bytes, rather than code points from Unicode or any other character repertoire. Within this specification, bytes are represented by their ASCII interpretations where these are printable characters.

Conceptually speaking, a script is translated using the following steps:

  1. Lexical analysis, which translates a stream of input characters into a stream of tokens.

  2. Syntactic analysis, which translates the stream of tokens into executable code.

Conforming implementations must accept scripts encoded with the UTF-8 encoding form (as defined by the Unicode standard), and transform them into a sequence of characters. Implementations can choose to accept and transform additional character encoding schemes.

Grammars

This specification shows the syntax of the PHP programming language using two grammars. The lexical grammar defines how source characters are combined to form white space, comments, and tokens. The syntactic grammar defines how the resulting tokens are combined to form PHP programs.

The grammars are presented using grammar productions, with each one defining a non-terminal symbol and the possible expansions of that non-terminal symbol into sequences of non-terminal or terminal symbols. In productions, non-terminal symbols are shown in slanted type like this, and terminal symbols are shown in a fixed-width font like this.

The first line of a grammar production is the name of the non-terminal symbol being defined, followed by one colon for a syntactic grammar production, and two colons for a lexical grammar production. Each successive indented line contains a possible expansion of the non-terminal given as a sequence of non-terminal or terminal symbols. For example, the production:

single-line-comment-example::
   //   input-charactersopt
   #   input-charactersopt

defines the lexical grammar production single-line-comment-example as being the terminals // or #, followed by an optional input-characters. Each expansion is listed on a separate line.

Although alternatives are usually listed on separate lines, when there is a large number, the shorthand phrase “one of” may precede a list of expansions given on a single line. For example,

hexadecimal-digit-example:: one of
   0   1   2   3   4   5   6   7   8   9
   a   b   c   d   e   f
   A   B   C   D   E   F

Lexical analysis

General

The production input-file is the root of the lexical structure for a script. Each script must conform to this production.

Syntax

input-file::
   input-element
   input-file   input-element

input-element::
   comment
   white-space
   token

Semantics

The basic elements of a script are comments, white space, and tokens.

The lexical processing of a script involves the reduction of that script into a sequence of tokens that becomes the input to the syntactic analysis. Tokens can be separated by white space and delimited comments.

Lexical processing always results in the creation of the longest possible lexical element. (For example, $a+++++$b must be parsed as $a++ ++ +$b, which syntactically is invalid).

Comments

Two forms of comments are supported: delimited comments and single-line comments.

Syntax

comment::
   single-line-comment
   delimited-comment

single-line-comment::
   //   input-charactersopt
   #   input-charactersopt

input-characters::
   input-character
   input-characters   input-character

input-character::
   Any source character except   new-line

new-line::
   Carriage-return character (0x0D)
   Line-feed character (0x0A)
   Carriage-return character (0x0D) followed by line-feed character (0x0A)

delimited-comment::
   /*   No characters or any source character sequence except */   */

Semantics

Except within a string literal or a comment, the characters /* start a delimited comment, which ends with the characters */. Except within a string literal or a comment, the characters // or # start a single-line comment, which ends with a new line. That new line is not part of the comment. However, if the single-line comment is the last source element in an embedded script, the trailing new line can be omitted. (Note: this allows for uses like <?php ... // ... ?>).

A delimited comment can occur in any place in a script in which white space can occur. (For example; /*...*/$c/*...*/=/*...*/567/*...*/;/*...*/ is parsed as $c=567;, and $k = $i+++/*...*/++$j; is parsed as $k = $i+++ ++$j;).

Implementation Notes

During tokenizing, an implementation can treat a delimited comment as though it was white space.

White Space

White space consists of an arbitrary combination of one or more new-line, space and horizontal tab characters.

Syntax

white-space::
   white-space-character
   white-space   white-space-character

white-space-character::
   new-line
   Space character (0x20)
   Horizontal-tab character (0x09)

Semantics

The space and horizontal tab characters are considered horizontal white-space characters.

Tokens

General

There are several kinds of source tokens:

Syntax

token::
   variable-name
   name
   keyword
   integer-literal
   floating-literal
   string-literal
   operator-or-punctuator

Names

Syntax

variable-name::
   $   name

namespace-name::
   name
   namespace-name   \   name

namespace-name-as-a-prefix::
   \
   \opt   namespace-name   \
   namespace   \
   namespace   \   namespace-name   \

qualified-name::
   namespace-name-as-a-prefixopt   name

name::
   name-nondigit
   name   name-nondigit
   name   digit

name-nondigit::
   nondigit
   one of the characters 0x80–0xff

nondigit:: one of
   _
   a   b   c   d   e   f   g   h   i   j   k   l   m
   n   o   p   q   r   s   t   u   v   w   x   y   z
   A   B   C   D   E   F   G   H   I   J   K   L   M
   N   O   P   Q   R   S   T   U   V   W   X   Y   Z

Semantics

Names are used to identify the following: constants, variables, labels, functions, classes, class members, interfaces, traits, namespaces, and names in heredoc and nowdoc comments.

A name begins with an underscore (_), name-nondigit, or extended name character in the range 0x80–-0xff. Subsequent characters can also include digits. A variable name is a name with a leading dollar ($).

Unless stated otherwise (functions, classes, methods, interfaces, traits, namespaces), names are case-sensitive, and every character in a name is significant.

Names beginning with two underscores (__) are reserved by the PHP language and should not be defined by the user code.

The following names cannot be used as the names of classes, interfaces, or traits: bool, FALSE, float, int, NULL, string, TRUE, iterable, and void.

The following names are reserved for future use and should not be used as the names of classes, interfaces, or traits: mixed, numeric, object, and resource.

With the exception of class, all keywords can be used as names for the members of a class, interface, or trait. However, class can be used as the name of a property or method.

Variable names and function names (when used in a function-call context) need not be defined as source tokens; they can also be created at runtime using simple variable expressions. (For example, given $a = "Total"; $b = 3; $c = $b + 5;, ${$a.$b.$c} = TRUE; is equivalent to $Total38 = TRUE;, and ${$a.$b.$c}() is equivalent to Total38()).

Examples

const MAX_VALUE = 100;
function getData() { /*...*/ }
class Point { /*...*/ }
interface ICollection { /*...*/ }

Implementation Notes

An implementation is discouraged from placing arbitrary restrictions on name lengths.

Keywords

A keyword is a name-like sequence of characters that is reserved, and cannot be used as a name.

Syntax

keyword:: one of
   abstract   and   array   as   break   callable   case   catch   class   clone
   const   continue   declare   default   die   do   echo   else   elseif   empty
   enddeclare   endfor   endforeach   endif   endswitch   endwhile   eval   exit
   extends   final   finally   for   foreach   function   global
   goto   if   implements   include   include_once   instanceof
   insteadof   interface   isset   list   namespace   new   or   print   private
   protected   public   require   require_once   return   static   switch
   throw   trait   try   unset   use   var   while   xor   yield   yield from

Semantics

Keywords are not case-sensitive.

Note carefully that yield from is a single token that contains whitespace. However, comments are not permitted in that whitespace.

Also, all magic constants are also treated as keywords.

Literals

The source code representation of a value is called a literal.

Integer Literals

Syntax

integer-literal::
   decimal-literal
   octal-literal
   hexadecimal-literal
   binary-literal

decimal-literal::
   nonzero-digit
   decimal-literal   digit

octal-literal::
   0
   octal-literal   octal-digit

hexadecimal-literal::
   hexadecimal-prefix   hexadecimal-digit
   hexadecimal-literal   hexadecimal-digit

hexadecimal-prefix:: one of
   0x   0X

binary-literal::
   binary-prefix   binary-digit
   binary-literal   binary-digit

binary-prefix:: one of
   0b   0B

digit:: one of
   0   1   2   3   4   5   6   7   8   9

nonzero-digit:: one of
   1   2   3   4   5   6   7   8   9

octal-digit:: one of
   0   1   2   3   4   5   6   7

hexadecimal-digit:: one of
   0   1   2   3   4   5   6   7   8   9
   a   b   c   d   e   f
   A   B   C   D   E   F

binary-digit:: one of
   0   1

Semantics

The value of a decimal integer literal is computed using base 10; that of an octal integer literal, base 8; that of a hexadecimal integer literal, base 16; and that of a binary integer literal, base 2.

If the value represented by integer-literal can fit in type int, that would be the type of the resulting value; otherwise, the type would be float, as described below.

Since negative numbers are represented in PHP as a negation of a positive number, the smallest negative value (-2147483648 for 32 bits and -9223372036854775808 for 64 bits) can not be represented as a decimal integer literal. If the non-negative value is too large to represent as an int, it becomes float, which is then negated.

Literals written using hexadecimal, octal, or binary notations are considered to have non-negative values.

An integer literal is always a constant expression.

Examples

$count = 10;      // decimal 10

0b101010 >> 4;    // binary 101010 and decimal 4

0XAF << 023;      // hexadecimal AF and octal 23

On an implementation using 32-bit int representation

2147483648 -> 2147483648 (too big for int, so is a float)

-2147483648 -> -2147483648 (too big for int, so is a float, negated)

-2147483647 - 1 -> -2147483648 fits in int

0x80000000 -> 2147483648 (too big for int, so is a float)
Floating-Point Literals

Syntax

floating-literal::
   fractional-literal   exponent-partopt
   digit-sequence   exponent-part

fractional-literal::
   digit-sequenceopt   .   digit-sequence
   digit-sequence   .

exponent-part::
   e   signopt   digit-sequence
   E   signopt   digit-sequence

sign:: one of
   +   -

digit-sequence::
   digit
   digit-sequence   digit

Constraints

The value of a floating-point literal must be representable by its type.

Semantics

The type of a floating-literal is float.

The constants INF and NAN provide access to the floating-point values for infinity and Not-a-Number, respectively.

A floating point literal is always a constant expression.

Examples

$values = array(1.23, 3e12, 543.678E-23);
String Literals

Syntax

string-literal::
   single-quoted-string-literal
   double-quoted-string-literal
   heredoc-string-literal
   nowdoc-string-literal

Semantics

A string literal is a sequence of zero or more characters delimited in some fashion. The delimiters are not part of the literal’s content.

The type of a string literal is string.

Single-Quoted String Literals

Syntax

single-quoted-string-literal::
   b-prefixopt   '   sq-char-sequenceopt   '

sq-char-sequence::
   sq-char
   sq-char-sequence   sq-char

sq-char::
   sq-escape-sequence
   \opt   any member of the source character set except single-quote (') or backslash (\)

sq-escape-sequence:: one of
   \'   \\

b-prefix:: one of
   b   B

Semantics

A single-quoted string literal is a string literal delimited by single-quotes (', 0x27). The literal can contain any source character except single-quote (') and backslash (\\), which can only be represented by their corresponding escape sequence.

The optional b-prefix is reserved for future use in dealing with so-called binary strings. For now, a single-quoted-string-literal with a b-prefix is equivalent to one without.

A single-quoted string literal is always a constant expression.

Examples

'This text is taken verbatim'

'Can embed a single quote (\') and a backslash (\\) like this'
Double-Quoted String Literals

Syntax

double-quoted-string-literal::
   b-prefixopt   "   dq-char-sequenceopt   "

dq-char-sequence::
   dq-char
   dq-char-sequence   dq-char

dq-char::
   dq-escape-sequence
   any member of the source character set except double-quote (") or backslash (\)
   \   any member of the source character set except "\$efnrtvxX or   octal-digit

dq-escape-sequence::
   dq-simple-escape-sequence
   dq-octal-escape-sequence
   dq-hexadecimal-escape-sequence
   dq-unicode-escape-sequence

dq-simple-escape-sequence:: one of
   \"   \\   \$   \e   \f   \n   \r   \t   \v

dq-octal-escape-sequence::
   \   octal-digit
   \   octal-digit   octal-digit
   \   octal-digit   octal-digit   octal-digit

dq-hexadecimal-escape-sequence::
   \x   hexadecimal-digit   hexadecimal-digitopt
   \X   hexadecimal-digit   hexadecimal-digitopt

dq-unicode-escape-sequence::
   \u{   codepoint-digits   }

codepoint-digits::
   hexadecimal-digit
   hexadecimal-digit   codepoint-digits

Semantics

A double-quoted string literal is a string literal delimited by double-quotes (", 0x22). The literal can contain any source character except double-quote (") and backslash (\\), which can only be represented by their corresponding escape sequence. Certain other (and sometimes non-printable) characters can also be expressed as escape sequences.

The optional b-prefix is reserved for future use in dealing with so-called binary strings. For now, a double-quoted-string-literal with a b-prefix is equivalent to one without.

An escape sequence represents a single-character encoding, as described in the table below:

Escape sequenceCharacter nameUnicode character
$Dollar sign0x24
"Double quote0x22
\Backslash0x5C
\eEscape0x1B
\fForm feed0x0C
\nNew line0x0A
\rCarriage Return0x0D
\tHorizontal Tab0x09
\vVertical Tab0x0B
\ooo1–3-digit octal digit value ooo
\xhh or \Xhh1–2-digit hexadecimal digit value hh
\u{xxxxxx}UTF-8 encoding of Unicode codepoint U+xxxxxxU+xxxxxx

Within a double-quoted string literal, except when recognized as the start of an escape sequence, a backslash (\) is retained verbatim.

Within a double-quoted string literal a dollar ($) character not escaped by a backslash (\) is handled using a variable substitution rules described below.

The \u{xxxxxx} escape sequence produces the UTF-8 encoding of the Unicode codepoint with the hexadecimal number specified within the curly braces. Implementations MUST NOT allow Unicode codepoints beyond U+10FFFF as this is outside the range UTF-8 can encode (see RFC 3629). If a codepoint larger than U+10FFFF is specified, implementations MUST error. Implementations MUST pass through \u verbatim and not interpret it as an escape sequence if it is not followed by an opening {, but if it is, implementations MUST produce an error if there is no terminating } or the contents are not a valid codepoint. Implementations MUST support leading zeroes, but MUST NOT support leading or trailing whitespace for the codepoint between the opening and terminating braces. Implementations MUST allow Unicode codepoints that are not Unicode scalar values, such as high and low surrogates.

A Unicode escape sequence cannot be created by variable substitution. For example, given $v = "41", "\u{$v}" results in "\u41", a string of length 4, while "\u{0$v}" and "\u{{$v}}" contain ill-formed Unicode escape sequences.

Variable substitution

The variable substitution accepts the following syntax:

string-variable::
   variable-name   offset-or-propertyopt
   ${   expression   }

offset-or-property::
   offset-in-string
   property-in-string

offset-in-string::
   [   name   ]
   [   variable-name   ]
   [   integer-literal   ]

property-in-string::
   ->   name

expression works the same way as in simple variable expressions.

After the variable defined by the syntax above is evaluated, its value is converted to string according to the rules of string conversion and is substituted into the string in place of the variable substitution expression.

Subscript or property access defined by offset-in-string and property-in-string is resolved according to the rules of the subscript operator and member access operator respectively. The exception is that name inside offset-in-string is interpreted as a string literal even if it is not quoted.

If the character sequence following the $ does not parse as name and does not start with {, the $ character is instead interpreted verbatim and no variable substitution is performed.

Variable substitution also provides limited support for the evaluation of expressions. This is done by enclosing an expression in a pair of matching braces ({ ... }). The opening brace must be followed immediately by a dollar ($) without any intervening white space, and that dollar must begin a variable name. If this is not the case, braces are treated verbatim. If the opening brace ({) is escaped it is not interpreted as a start of the embedded expression and instead is interpreted verbatim.

The value of the expression is converted to string according to the rules of string conversion and is substituted into the string in place of the substitution expression.

A double-quoted string literal is a constant expression if it does not contain any variable substitution.

Examples

$x = 123;
echo ">\$x.$x"."<"; // → >$x.123<
// -----------------------------------------
$colors = array("red", "white", "blue");
$index = 2;
echo "\$colors[$index] contains >$colors[$index]<\n";
  // → $colors[2] contains >blue<
// -----------------------------------------
class C {
    public $p1 = 2;
}
$myC = new C();
echo "\$myC->p1 = >$myC->p1<\n";  // → $myC->p1 = >2<
Heredoc String Literals

Syntax

heredoc-string-literal::
   b-prefixopt   <<<   hd-start-identifier   new-line   hd-bodyopt   hd-end-identifier   ;opt   new-line

hd-start-identifier::
   name
   "   name   "

hd-end-identifier::
   name

hd-body::
   hd-char-sequenceopt   new-line

hd-char-sequence::
   hd-char
   hd-char-sequence   hd-char

hd-char::
   hd-escape-sequence
   any member of the source character set except backslash (\)
   \ any member of the source character set except \$efnrtvxX or   octal-digit

hd-escape-sequence::
   hd-simple-escape-sequence
   dq-octal-escape-sequence
   dq-hexadecimal-escape-sequence
   dq-unicode-escape-sequence

hd-simple-escape-sequence:: one of
   \\   \$   \e   \f   \n   \r   \t   \v

Constraints

The start and end identifier names must be the same. Only horizontal white space is permitted between <<< and the start identifier. No white space is permitted between the start identifier and the new-line that follows. No white space is permitted between the new-line and the end identifier that follows. Except for an optional semicolon (;), no characters—-not even comments or white space-—are permitted between the end identifier and the new-line that terminates that source line.

Semantics

A heredoc string literal is a string literal delimited by “<<< name” and “name”. The literal can contain any source character. Certain other (and sometimes non-printable) characters can also be expressed as escape sequences.

A heredoc literal supports variable substitution as defined for double-quoted string literals.

A heredoc string literal is a constant expression if it does not contain any variable substitution.

The optional b-prefix has no effect.

Examples

$v = 123;
$s = <<<    ID
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<";
// → >S'o'me "\"t e  xt; $v = 123"
// Some more text<
Nowdoc String Literals

Syntax

nowdoc-string-literal::
   b-prefixopt   <<<   '   name   '   new-line   hd-bodyopt   name   ;opt   new-line

Constraints

The start and end identifier names must be the same. No white space is permitted between the start identifier name and its enclosing single quotes ('). See also heredoc string literal.

Semantics

A nowdoc string literal looks like a heredoc string literal except that in the former the start identifier name is enclosed in single quotes ('). The two forms of string literal have the same semantics and constraints except that a nowdoc string literal is not subject to variable substitution (like the single-quoted string).

A nowdoc string literal is a constant expression.

The optional b-prefix has no effect.

Examples

$v = 123;
$s = <<<    'ID'
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<\n\n";
// → >S'o'me "\"t e\txt; \$v = $v"
// Some more text<

Operators and Punctuators

Syntax

operator-or-punctuator:: one of
   [   ]   (   )   {   }   .   ->   ++   --   **   *   +   -   ~   !
   $   /   %   <<   >>   <   >   <=   >=   ==   ===   !=   !==   ^   |
   &   &&   ||   ?   :   ;   =   **=   *=   /=   %=   +=   -=   .=   <<=
   >>=   &=   ^=   |=   ,   ??   <=>   ...   \

Semantics

Operators and punctuators are symbols that have independent syntactic and semantic significance. Operators are used in expressions to describe operations involving one or more operands, and that yield a resulting value, produce a side effect, or some combination thereof. Punctuators are used for grouping and separating.

Expressions

General

An expression involves one or more terms and zero or more operators.

A full expression is an expression that is not part of another expression.

A side effect is an action that changes the state of the execution environment. (Examples of such actions are modifying a variable, writing to a device or file, or calling a function that performs such operations).

When an expression is evaluated, it produces a result. It might also produce a side effect. Only a few operators produce side effects. (For example, given the expression statement $v = 10; the expression 10 is evaluated to the result 10, and there is no side effect. Then the assignment operator is executed, which results in the side effect of $v being modified. The result of the whole expression is the value of $v after the assignment has taken place. However, that result is never used. Similarly, given the expression statement ++$v; the expression is evaluated to the result incremented-value-of-$v, and the side effect is that $v is actually incremented. Again, the result is never used).

The occurrence of value computation and side effects is delimited by sequence points, places in a program’s execution at which all the computations and side effects previously promised are complete, and no computations or side effects of future operations have yet begun. There is a sequence point at the end of each full expression. The logical and, logical or, conditional, coalesce and function call operators each contain a sequence point. (For example, in the following series of expression statements, $a = 10; ++$a; $b = $a;, there is sequence point at the end of each full expression, so the assignment to $a is completed before $a is incremented, and the increment is completed before the assignment to $b).

When an expression contains multiple operators, the precedence of those operators controls the order in which those operators are applied. (For example, the expression $a - $b / $c is evaluated as $a - ($b / $c) because the / operator has higher precedence than the binary - operator). The precedence of an operator is determined by the definition of its associated grammar production.

If an operand occurs between two operators having the same precedence, the order in which the operations are performed is determined by those operators’ associativity. With left-associative operators, operations are performed left-to-right. (For example, $a + $b - $c is evaluated as ($a + $b) - $c). With right-associative operators, operations are performed right-to-left. (For example, $a = $b = $c is evaluated as $a = ($b = $c)).

Precedence and associativity can be controlled using grouping parentheses. (For example, in the expression ($a - $b) / $c, the subtraction is done before the division. Without the grouping parentheses, the division would take place first).

While precedence, associativity, and grouping parentheses control the order in which operators are applied, they do not control the order of evaluation of the terms themselves. Unless stated explicitly in this specification, the order in which the operands in an expression are evaluated relative to each other is unspecified. See the discussion above about the operators that contain sequence points. (For example, in the full expression $list1[$i] = $list2[$i++], whether the value of $i on the left-hand side is the old or new $i, is unspecified. Similarly, in the full expression $j = $i + $i++, whether the value of $i is the old or new $i, is unspecified. Finally, in the full expression f() + g() * h(), the order in which the three functions are called, is unspecified).

Implementation Notes

An expression that contains no side effects and whose resulting value is not used need not be evaluated. For example, the expression statements 6;, $i + 6;, and $i/$j; are well formed, but they contain no side effects and their results are not used.

A side effect need not be executed if it can be determined that no other program code relies on its having happened. (For example, in the cases of return $a++; and return ++$a;, it is obvious what value must be returned in each case, but if $a is a variable local to the enclosing function, $a need not actually be incremented.

Primary Expressions

General

Syntax

primary-expression:
   variable
   class-constant-access-expression
   constant-access-expression
   literal
   array-creation-expression
   intrinsic
   anonymous-function-creation-expression
   object-creation-expression
   postfix-increment-expression
   postfix-decrement-expression
   prefix-increment-expression
   prefix-decrement-expression
   byref-assignment-expression
   shell-command-expression
   (   expression   )

Semantics

The type and value of parenthesized expression are identical to those of the un-parenthesized expression.

Simple Variable

Syntax

simple-variable:
   variable-name
   $   simple-variable
   $   {   expression   }

Constraints

The simple-variable or expression in the last two variants must designate a scalar value or object convertible to string.

Semantics

A simple-variable expression designates a variable with the name determined by either the variable-name or the string representation of the result of the simple-variable or expression, depending on which case is applicable. In the latter two cases the variable name may contain characters that are not allowed in a lexical variable-name.

The behavior of a simple-variable in different contexts and for different types of variables is as specified in the variables section.

The variable $this is predefined inside any non-static instance method (including constructor) when that method is called from within an object context. The value of $this is the calling object or the object being constructed.

Examples

$color = "red";
$$color = 123;    // equivalent to $red = 123
// -----------------------------------------
$x = 'ab'; $ab = 'fg'; $fg = 'xy';
$$ $ $x = 'Hello';  // equivalent to $xy = Hello
// -----------------------------------------
$v1 = 3;
$$v1 = 22;        // equivalent to ${3} = 22, variable name is "3"
$v2 = 9.543;
$$v2 = TRUE;    // equivalent to ${9.543} = TRUE
$v3 = NULL;
$$v3 = "abc";   // equivalent to ${NULL} = "abc", here we create a variable with empty name
// -----------------------------------------
function f1 () { return 2.5; }
${1 + f1()} = 1000;   // equivalent to ${3.5} = 1000

Dereferencable expression

Syntax

dereferencable-expression:
   variable
   (   expression   )
   array-creation-expression
   string-literal

callable-expression:
   callable-variable
   (   expression   )
   array-creation-expression
   string-literal

Constraints

The string-literal must not use variable interpolation and must not be a heredoc or nowdoc string literal.

Semantics

A dereferencable-expression can be used as the left hand side of dereferencing operators, such as [], -> and ::. A callable-expression can be used as the left hand side of the function call operator.

Variables

Syntax

callable-variable:
   simple-variable
   subscript-expression
   member-call-expression
   scoped-call-expression
   function-call-expression

variable:
   callable-variable
   scoped-property-access-expression
   member-access-expression

Semantics

A variable is an expression that can in principle be used as an lvalue. However, the individual possible expressions may further restrict whether they can behave as lvalues. An expression that is not a variable can never act as an lvalue.

Constant Access Expression

constant-access-expression:
   qualified-name

Semantics

A constant-access-expression evaluates to the value of the constant with name qualified-name.

Literals

Syntax

literal:
   integer-literal
   floating-literal
   string-literal

Semantics

A literal evaluates to its value, as specified in the lexical specification for literals.

Intrinsics

General

Syntax

intrinsic:
   empty-intrinsic
   eval-intrinsic
   exit-intrinsic
   isset-intrinsic

Semantics

The names in this series of sections have special meaning and are called intrinsics, but they are not keywords; nor are they functions, they are language constructs that are interpreted by the Engine.

empty

Syntax

empty-intrinsic:
   empty   (   expression   )

Semantics

This intrinsic returns TRUE if the variable or value designated by expression is empty, where empty means that the variable designated by it does not exist, or it exists and its value compares equal to FALSE. Otherwise, the intrinsic returns FALSE.

The following values are considered empty: FALSE, 0, 0.0, "" (empty string), "0", NULL, an empty array, and any uninitialized variable.

If this intrinsic is used with an expression that designates a dynamic property, then if the class of that property has an __isset, that method is called. If that method returns TRUE, the value of the property is retrieved (which may call __get if defined) and compared to FALSE as described above. Otherwise, the result is FALSE.

Examples

empty("0");  // results in TRUE
empty("00"); // results in FALSE
$v = [10, 20];
empty($v);   // results in FALSE

eval

Syntax

eval-intrinsic:
   eval   (   expression   )

Constraints

expression must designate a string, or be convertable to a string. The contents of the string must be valid PHP source code. If the source code is ill formed, an exception of type ParseError is thrown.

The PHP source code in the string must not be delimited by opening and closing PHP tags. However, the source code itself may contain the tags.

Semantics

This intrinsic evaluates the contents of the string designated by expression, as PHP script code.

Execution of a return statement from within the source code terminates the execution, and the value returned becomes the value returned by eval. If the source code is ill formed, eval returns FALSE; otherwise, eval returns NULL.

The source code is executed in the scope of that from which eval is called.

Examples

$str = "Hello";
eval("echo \$str . \"\\n\";");  // → echo $str . "\n"; → prints Hello

exit/die

Syntax

exit-intrinsic:
   exit
   exit   (   expressionopt   )
   die
   die   (   expressionopt   )

Constraints

When expression designates an integer, its value must be in the range 0–254.

Semantics

exit and die are equivalent.

This intrinsic terminates the current script. If expression designates a string, that string is written to STDOUT. If expression designates an integer, that represents the script’s exit status code. Code 255 is reserved by PHP. Code 0 represents “success”. The exit status code is made available to the execution environment. If expression is omitted or is a string, the exit status code is zero. exit does not have a resulting value.

exit performs the following operations, in order:

Examples

exit ("Closing down");
exit (1);
exit;

isset

Syntax

isset-intrinsic:
   isset   (   variable-list   ,opt   )

variable-list:
   variable
   variable-list   ,   variable

Semantics

This intrinsic returns TRUE if all the variables designated by variabless are set and their values are not NULL. Otherwise, it returns FALSE.

If this intrinsic is used with an expression that designate a dynamic property, then if the class of that property has an __isset, that method is called. If that method returns TRUE, the value of the property is retrieved (which may call __get if defined) and if it is not NULL, the result is TRUE. Otherwise, the result is FALSE.

Examples

$v = TRUE;
isset($v);     // results in TRUE
$v = NULL;
isset($v);     // results in FALSE
$v1 = TRUE; $v2 = 12.3; $v3 = NULL;
isset($v1, $v2, $v3);  // results in FALSE

Anonymous Function Creation

Syntax

anonymous-function-creation-expression:
   staticopt   function   &opt   (   parameter-declaration-listopt   )   anonymous-function-use-clauseopt   return-typeopt   compound-statement

anonymous-function-use-clause:
   use   (   use-variable-name-list   )

use-variable-name-list:
   &opt   variable-name
   use-variable-name-list   ,   &opt   variable-name

Semantics

This operator returns an object of type Closure, or a derived type thereof, that encapsulates the anonymous function defined within. An anonymous function is defined like, and behaves like, a named function except that the former has no name and has an optional anonymous-function-use-clause.

An expression that designates an anonymous function is compatible with the pseudo-type callable.

The use-variable-name-list is a list of variables from the enclosing scope, which are to be made available by name to the body of the anonymous function. Each of these may be passed by value or byRef, as needed. The values used for these variables are those at the time the Closure object is created, not when it is used to call the function it encapsulates.

An anonymous function defined inside an instance or static method has its scope set to the class it was defined in. Otherwise, an anonymous function is unscoped.

An anonymous function defined inside an instance method is bound to the object on which that method is called, while an an anonymous function defined inside a static method, or prefixed with the optional static modifier is static, and otherwise an anonymous function is unbound.

Examples

function doit($value, callable $process)
{
  return $process($value);
}
$result = doit(5, function ($p) { return $p * 2; });  // doubles a value
$result = doit(5, function ($p) { return $p * $p; }); // squares a value
// -----------------------------------------
class C
{
  public function compute(array $values)
  {
    $count = 0;
    $callback1 = function () use (&$count) // has C as its scope
    {
      ++$count;
      //...
    };
    //...
    $callback2 = function()   // also has C as its scope
    {
      //...
    };
    //...
  }
  //...
}

The new Operator

Syntax

object-creation-expression:
   new   class-type-designator   (   argument-expression-listopt   )
   new   class-type-designator   (   argument-expression-list   ,opt   )
   new   class-type-designator
   new   class   (   argument-expression-listopt   )   class-base-clauseopt   class-interface-clauseopt   {   class-member-declarationsopt   }
   new   class   class-base-clauseopt   class-interface-clauseopt   {   class-member-declarationsopt   }

class-type-designator:
   qualified-name
   new-variable

new-variable:
   simple-variable
   new-variable   [   expressionopt   ]
   new-variable   {   expression   }
   new-variable   ->   member-name
   qualified-name   ::   simple-variable
   relative-scope   ::   simple-variable
   new-variable   ::   simple-variable

Constraints

qualified-name must name a class.

new-variable must be a value of type string that contains the name of a class, or an object.

class-type-designator must not designate an abstract class.

The number of arguments in argument-expression-list must be at least as many as the number of non-optional parameters defined for the class’s constructor.

Semantics

The new class-type-designator forms create an object of the class type specified by class-type-designator. The new class forms create an object of an anonymous class type, a type that has an unspecified name. In all other respects, however, an anonymous class has the same capabilities as a named class type.

If the class-type-designator is a new-variable resulting in a string value, that string is used as the class name. If the expression results in an object, the class of the object is used as the class for the new object. The new-variable has the same semantics as a variable, but the grammar is restricted to exclude calls.

The qualified-name is resolved according to the rules described in scope resolution operator, including support for self, parent and static.

After the object has been created, each instance property is initialized with the values specified in property definition, or the value NULL if no initializer value is provided.

The object is then initialized by calling the class’s constructor passing it the optional argument-expression-list. If the class has no constructor, the constructor that class inherits (if any) is used. The class can also specify no constructor definition, in this case the constructor call is omitted.

The result of a named-type object-creation-expression is an object of the type specified by class-type-designator. The result of an anonymous class object-creation-expression is an object of unspecified type. However, this type will subtype all types provided by class-base-clause and class-interface-clause and the class-members definition should follow the same inheritance and implementation rules as the regular class declaration does.

Each distinct source code expression of the form new class results in the class type that is different from that of all other anonymous class types. However, multiple evaluations of the same source code expression of the form new class result in instances of the same class type.

Because a constructor call is a function call, the relevant parts of function call operator section also apply.

Examples

class Point
{
  public function __construct($x = 0, $y = 0)
  {
    ...
  }
  ...
}
$p1 = new Point;     // create Point(0, 0)
$p1 = new Point(12);   // create Point(12, 0)
$cName = 'Point';
$p1 = new $cName(-1, 1); // create Point(-1, 1)
// -----------------------------------------
$v2 = new class (100) extends C1 implements I1, I2 {
	public function __construct($p) {
	    echo "Inside class " . __CLASS__ . " constructor with parameter $p\n";
	}
};

Array Creation Operator

Syntax

array-creation-expression:
   array   (   array-initializeropt   )
   [   array-initializeropt   ]

array-initializer:
   array-initializer-list   ,opt

array-initializer-list:
   array-element-initializer
   array-element-initializer   ,   array-initializer-list

array-element-initializer:
   &opt   element-value
   element-key   =>   &opt   element-value

element-key:
   expression

element-value:
   expression

Constraints

If array-element-initializer contains &, expression in element-value must designate a variable.

Semantics

If array-initializer is omitted, the array has zero elements. For convenience, an array-initializer may have a trailing comma; however, this comma is ignored. An array-initializer-list consists of a comma-separated list of one or more array-element-initializer items, each of which is used to provide an element-value and an optional element-key.

If the type of element-key is neither int nor string, keys with float or bool values, or strings whose contents match exactly the pattern of decimal-literal, are converted to integer, and keys of all other types are converted to string.

If element-key is omitted from an array-element-initializer, an element key of type int is associated with the corresponding element-value. The key associated is one more than the largest previously assigned non-negative int key for this array, regardless of whether that key was provided explicitly or by default. If the array has no non-negative int keys, the key 0 is used. If the largest previously assigned int key is the largest integer value that can be represented, the new element is not added.

Once the element keys have been converted to int or string, and omitted element keys have each been associated by default, if two or more array-element-initializer elements in an array-initializer contain the same key, the lexically right-most one is the one whose element-value is used to initialize that element.

The result of this operator is the newly created array value.

If array-element-initializer contains &, element-value’s value is stored using byRef assignment.

Examples

$v = [];      // array has 0 elements, i.e. empty array
$v = array(TRUE);   // array has 1 element, the Boolean TRUE
$v = [123, -56];  // array of two ints, with implicit int keys 0 and 1
$v = [0 => 123, 1 => -56]; // array of two ints, with explicit int keys 0 and 1
$i = 10;
$v = [$i - 10 => 123, $i - 9 => -56]; // key can be a runtime expression
$v = [NULL, 1 => FALSE, 123, 3 => 34e12, "Hello"];  // implicit & explicit keys
$i = 6; $j = 12;
$v = [7 => 123, 3 => $i, 6 => ++$j];  // keys are in arbitrary order
$v[4] = 99;   // extends array with a new element
$v = [2 => 23, 1 => 10, 2 => 46, 1.9 => 6];
     // array has 2, with keys 2 and 1, values 46 and 6, respectively
$v = ["red" => 10, "4" => 3, 9.2 => 5, "12.8" => 111, NULL => 1];
     // array has 5 elements, with keys “red”, 4, 9, “12.8”, and “”.
$c = array("red", "white", "blue");
$v = array(10, $c, NULL, array(FALSE, NULL, $c));
$v = array(2 => TRUE, 0 => 123, 1 => 34.5, -1 => "red");
foreach($v as $e) { /* ... */ } // iterates over keys 2, 0, 1, -1
for ($i = -1; $i <= 2; ++$i) { echo $v[$i]; } // retrieves via keys -1, 0, 1, 2

Subscript Operator

Syntax

subscript-expression:
   dereferencable-expression   [   expressionopt   ]
   dereferencable-expression   {   expression   }   <b>[Deprecated form]</b>

Constraints

If dereferencable-expression designates a string, expression must not designate a string.

expression can be omitted only if subscript-expression is used in a modifiable-lvalue context and dereferencable-expression does not designate a string. Exception from this is when dereferencable-expression is an empty string - then it is converted to an empty array.

If subscript-expression is used in a non-lvalue context, the element being designated must exist.

Semantics

A subscript-expression designates a (possibly non-existent) element of an array or string. When subscript-expression designates an object of a type that implements ArrayAccess, the minimal semantics are defined below; however, they can be augmented by that object’s methods offsetGet and offsetSet.

The element key is designated by expression. If the type of element-key is neither int nor string, keys with float or bool values, or strings whose contents match exactly the pattern of decimal-literal, are converted to integer, and key values of all other types are converted to string.

If both dereferencable-expression and expression designate strings, expression is treated as if it specified the int key zero instead and a non-fatal error is produces.

A subscript-expression designates a modifiable lvalue if and only if dereferencable-expression designates a modifiable lvalue.

dereferencable-expression designates an array

If expression is present, if the designated element exists, the type and value of the result is the type and value of that element; otherwise, the result is NULL.

If expression is omitted, a new element is inserted. Its key has type int and is one more than the highest, previously assigned int key for this array. If this is the first element with an int key, key 0 is used. If the largest previously assigned int key is the largest integer value that can be represented, the new element is not added. The result is the added new element, or NULL if the element was not added.

dereferencable-expression designates a string

The expression is converted to int and the result is the character of the string at the position corresponding to that integer. If the integer is negative, the position is counted backwards from the end of the string. If the position refers to a non-existing offset, the result is an empty string.

If the operator is used as the left-hand side of a simple-assignment-expression,

  • If the assigned string is empty, or in case of non-existing negative offset (absolute value larger than string length), a warning is raised and no assignment is performed.
  • If the offset is larger than the current string length, the string is extended to a length equal to the offset value, using space (0x20) padding characters.
  • The value being assigned is converted to string and the character in the specified offset is replaced by the first character of the string.

The subscript operator can not be used on a string value in a byRef context or as the operand of the postfix- or prefix-increment or decrement operators or on the left side of compound-assignment-expression, doing so will result in a fatal error.

dereferencable-expression designates an object of a type that implements ArrayAccess

If expression is present,

  • If subscript-expression is used in a non-lvalue context, the object’s method offsetGet is called with an argument of expression. The return value of the offsetGet is the result.
  • If the usage context is as the left-hand side of a simple-assignment-expression, the object’s method offsetSet is called with a first argument of expression and a second argument that is the value of the right-hand side of that simple-assignment-expression. The value of the right-hand side is the result.
  • If the usage context is as the left-hand side of a compound-assignment-expression, the expression e1[e] op= e2 is evaluated as e1[e] = e1->offsetGet(e) op (e2), which is then processed according to the rules for simple assignment immediately above.
  • If the usage context is as the operand of the postfix- or prefix-increment or decrement operators, the object’s method offsetGet is called with an argument of expression. However, this method has no way of knowing if an increment or decrement operator was used, or whether it was a prefix or postfix operator. In order for the value to be modified by the increment/decrement, offsetGet must return byRef. The result of the subscript operator value returned by offsetGet.

If expression is omitted,

  • If the usage context is as the left-hand side of a simple-assignment-expression, the object’s method offsetSet is called with a first argument of NULL and a second argument that is the value of the right-hand side of that simple-assignment-expression. The type and value of the result is the type and value of the right-hand side of that simple-assignment-expression.
  • If the usage context is as the left-hand side of a compound-assignment-expression: The expression e1[] op= e2 is evaluated as e1[] = e1->offsetGet(NULL) op (e2), which is then processed according to the rules for simple assignment immediately above.
  • If the usage context is as the operand of the postfix- or prefix-increment or decrement operators, the object’s method offsetGet is called with an argument of NULL. However, this method has no way of knowing if an increment or decrement operator was used, or whether it was a prefix or postfix operator. In order for the value to be modified by the increment/decrement, offsetGet must return byRef. The result of the subscript operator value returned by offsetGet.

Note: The brace ({...}) form of this operator has been deprecated.

Examples

$v = array(10, 20, 30);
$v[1] = 1.234;    // change the value (and type) of element [1]
$v[-10] = 19;   // insert a new element with int key -10
$v["red"] = TRUE; // insert a new element with string key "red"
[[2,4,6,8], [5,10], [100,200,300]][0][2]  // designates element with value 6
["black", "white", "yellow"][1][2]  // designates substring "i" in "white"
function f() { return [1000, 2000, 3000]; }
f()[2];      // designates element with value 3000
"red"[1.9];    // designates "e"
"red"[-2];    // designates "e"
"red"[0][0][0];    // designates "r"
// -----------------------------------------
class MyVector implements ArrayAccess { /* ... */ }
$vect1 = new MyVector(array(10, 'A' => 2.3, "up"));
$vect1[10] = 987; // calls Vector::offsetSet(10, 987)
$vect1[] = "xxx"; // calls Vector::offsetSet(NULL, "xxx")
$x = $vect1[1];   // calls Vector::offsetGet(1)

Function Call Operator

Syntax

function-call-expression:
   qualified-name   (   argument-expression-listopt   )
   qualified-name   (   argument-expression-list   ,   )
   callable-expression   (   argument-expression-listopt   )
   callable-expression   (   argument-expression-list   ,   )

argument-expression-list:
   argument-expression
   argument-expression-list   ,   argument-expression

argument-expression:
   variadic-unpacking
   expression

variadic-unpacking:
   ...   expression

Constraints

callable-expression must designate a function, by being a value of type string that contains the function’s name, or by being an object of a type that implements __invoke method (including Closure objects).

The number of arguments present in a function call must be at least as many as the number of non-optional parameters defined for that function.

No calls can be made to a conditionally defined function until that function exists.

Any argument that matches a parameter passed byRef should (but need not) designate an lvalue.

If variadic-unpacking is used, the result of the expression must be an array or Traversable. If incompatible value is supplied, the argument is ignored and a non-fatal error is issued.

Semantics

An expression of the form function-call-expression is a function call. The expression designates the called function, and argument-expression-list specifies the arguments to be passed to that function. An argument can be any value. In a function call, callable-expression is evaluated first, followed by each expression in the order left-to-right. There is a sequence point after each argument is evaluated and right before the function is called. For details of the result of a function call see return statement. The value of a function call is a modifiable lvalue only if the function returns a modifiable value byRef.

When a function is called, the value of each argument passed to it is assigned to the corresponding parameter in that function’s definition, if such a parameter exists. The assignment of argument values to parameters is defined in terms of simple or byRef assignment, depending on how the parameter was declared. There may be more arguments than parameters, in which case, the library functions func_num_args, func_get_arg and func_get_args can be used to get access to the complete argument list that was passed. If the number of arguments present in a function call is fewer than the number of parameters defined for that function, any parameter not having a corresponding argument is considered undefined if it has no default argument value; otherwise, it is considered defined with that default argument value.

If an undefined variable is passed using byRef, that variable becomes defined, with an initial value of NULL.

Direct and indirect recursive function calls are permitted.

If callable-expression is a string, this is a variable function call.

If variadic-unpacking operation is used, the operand is considered to be a parameter list. The values contained in the operand are fetched one by one (in the same manner as foreach would do) and used for next arguments of for the call. The keys for in the iteration are ignored.

Multiple unpacking operations can be used in the same function call, and unpacking and regular parameters can be mixed in any order.

Examples

function square($v) { return $v * $v; }
square(5);     // call square directly; it returns 25
$funct = square;  // assigns the string "square" to $funct
$funct(-2.3)    // call square indirectly; it returns 5.29
strlen($lastName); // returns the # of bytes in the string
// -----------------------------------------
function f1() { ... }  function f2() { ... }  function f3() { ... }
for ($i = 1; $i <= 2; ++$i) { $f = 'f' . $i;  $f(); }
// -----------------------------------------
function f($p1, $p2, $p3, $p4, $p5) { ... }
function g($p1, $p2, $p3, $p4, $p5) { ... }
function h($p1, $p2, $p3, $p4, $p5) { ... }
$funcTable = array(f, g, h);  // list of 3 function designators
$i = 1;
$funcTable[$i++]($i, ++$i, $i, $i = 12, --$i); // calls g(2,3,3,12,11)
// -----------------------------------------
function f4($p1, $p2 = 1.23, $p3 = "abc") { ... }
f4(); // inside f4, $p1 is undefined, $p2 is 1.23, $p3 is "abc"
// -----------------------------------------
function f(&$p) { ... }
$a = array(10, 20, 30);
f($a[5]); // non-existent element going in, but element exists afterwards
// -----------------------------------------
function factorial($int)  // contains a recursive call
{
  return ($int > 1) ? $int * factorial($int - 1) : $int;
}
// -----------------------------------------
$anon = function () { ... };  // store a Closure in $anon
$anon();  // call the anonymous function encapsulated by that object

Member Access Operator

Syntax

member-access-expression:
   dereferencable-expression   ->   member-name

member-name:
   name
   simple-variable
   {   expression   }

Constraints

The dereferencable-expression must designate an object or be NULL, FALSE, or an empty string.

expression must be a value of type string (but not a string literal) that contains the name of an instance property (without the leading $) or an instance or static method of that instance’s class type.

Semantics

A member-access-expression designates an instance property of the object designated by dereferencable-expression with the name given by the string representation of member-name. The value is that of the property, and is a modifiable lvalue if dereferencable-expression is a modifiable lvalue.

When the -> operator is used in a modifiable lvalue context and member-name designate a property that is not visible, the property is treated as a dynamic property. If dereferencable-expression’s class type defines a __set method, it is called to store the property’s value. When the -> operator is used in a non-lvalue context and member-name designate a property that is not visible, the property is treated as a dynamic property. If dereferencable-expression’s class type defines a __get method, it is called to retrieve the property’s value.

If dereferencable-expression is NULL, FALSE, or an empty string, an expression of the form $p->x = 10 causes an instance of stdClass to be created with a dynamic property x having a value of 10. $p is then made to refer to this instance.

Examples

class Point
{
  private $x;
  private $y;
  public function move($x, $y)
  {
    $this->x = $x;  // sets private property $x
    $this->y = $y;  // sets private property $x
  }
  public function __toString()
  {
    return '(' . $this->x . ',' . $this->y . ')';
  }
  // get private properties $x and $y
  public function __set($name, $value) { ... }
  public function __get($name) { ... }
}
$p1 = new Point;
$p1->move(3, 9);  // calls public instance method move by name
$n = "move";
$p1->$n(-2, 4);   // calls public instance method move by variable
$p1->color = "red"; // turned into $p1->__set("color", "red");
$c = $p1->color;  // turned into $c = $p1->__get("color");

Member Call Operator

Syntax

member-call-expression:
   dereferencable-expression   ->   member-name   (   argument-expression-listopt   )
   dereferencable-expression   ->   member-name   (   argument-expression-list   ,   )

Constraints

The dereferencable-expression must designate an object.

Additionally the general function call constraints apply.

Semantics

A member-call-expression calls an instance or static method of the object designated by dereferencable-expression, with the method name given by the string representation of member-name and the arguments given by argument-expression-list. The value of dereferencable-expression is used as the value of $this in the invoked method.

The general function call semantics apply.

If the called method does not exist or is not visible from the current scope an exception is thrown, unless a __call method exists, in which case it will be called instead.

Examples

See member access examples.

Postfix Increment and Decrement Operators

Syntax

postfix-increment-expression:
   variable   ++

postfix-decrement-expression:
   variable   --

Constraints

The operand of the postfix ++ and – operators must be a modifiable lvalue that has scalar-compatible type.

Semantics

These operators behave like their prefix counterparts except that the value of a postfix ++ or – expression is the value before any increment or decrement takes place.

Examples

$i = 10; $j = $i-- + 100;   // old value of $i (10) is added to 100
$a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned

Prefix Increment and Decrement Operators

Syntax

prefix-increment-expression:
   ++   variable

prefix-decrement-expression:
   --   variable

Constraints

The operand of the prefix ++ or -- operator must be a modifiable lvalue that has scalar-compatible type.

Semantics

Arithmetic Operands

For a prefix ++ operator used with an arithmetic operand, the side effect of the operator is to increment the value of the operand by 1. The result is the value of the operand after it has been incremented. If an int operand’s value is the largest representable for that type, the operand is incremented as if it were float.

For a prefix -- operator used with an arithmetic operand, the side effect of the operator is to decrement the value of the operand by 1. The result is the value of the operand after it has been decremented. If an int operand’s value is the smallest representable for that type, the operand is decremented as if it were float.

For a prefix ++ or -- operator used with an operand having the value INF, -INF, or NAN, there is no side effect, and the result is the operand’s value.

Boolean Operands

For a prefix ++ or -- operator used with a Boolean-valued operand, there is no side effect, and the result is the operand’s value.

NULL-valued Operands

For a prefix – operator used with a NULL-valued operand, there is no side effect, and the result is the operand’s value. For a prefix ++ operator used with a NULL-valued operand, the side effect is that the operand’s type is changed to int, the operand’s value is set to zero, and that value is incremented by 1. The result is the value of the operand after it has been incremented.

String Operands

For a prefix -- operator used with an operand whose value is an empty string, the side effect is that the operand’s type is changed to int, the operand’s value is set to zero, and that value is decremented by 1. The result is the value of the operand after it has been incremented.

For a prefix ++ operator used with an operand whose value is an empty string, the side effect is that the operand’s value is changed to the string “1”. The type of the operand is unchanged. The result is the new value of the operand.

For a prefix -- or ++ operator used with a numeric string, the numeric string is treated as the corresponding int or float value.

For a prefix -- operator used with a non-numeric string-valued operand, there is no side effect, and the result is the operand’s value.

For a non-numeric string-valued operand that contains only alphanumeric characters, for a prefix ++ operator, the operand is considered to be a representation of a base-36 number (i.e., with digits 0–9 followed by A–Z or a–z) in which letter case is ignored for value purposes. The right-most digit is incremented by 1. For the digits 0–8, that means going to 1–9. For the letters “A”–“Y” (or “a”–“y”), that means going to “B”–“Z” (or “b”–“z”). For the digit 9, the digit becomes 0, and the carry is added to the next left-most digit, and so on. For the digit “Z” (or “z”), the resulting string has an extra digit “A” (or “a”) appended. For example, when incrementing, “a” -> “b”, “Z” -> “AA”, “AA” -> “AB”, “F29” -> “F30”, “FZ9” -> “GA0”, and “ZZ9” -> “AAA0”. A digit position containing a number wraps modulo-10, while a digit position containing a letter wraps modulo-26.

For a non-numeric string-valued operand that contains any non-alphanumeric characters, for a prefix ++ operator, all characters up to and including the right-most non-alphanumeric character is passed through to the resulting string, unchanged. Characters to the right of that right-most non-alphanumeric character are treated like a non-numeric string-valued operand that contains only alphanumeric characters, except that the resulting string will not be extended. Instead, a digit position containing a number wraps modulo-10, while a digit position containing a letter wraps modulo-26.

Object Operands

If the operand has an object type supporting the operation, then the object semantics defines the result. Otherwise, the operation has no effect and the result is the operand.

Examples

$i = 10; $j = --$i + 100;   // new value of $i (9) is added to 100
$a = array(100, 200); $v = ++$a[1]; // new value of $a[1] (201) is assigned
$a = "^^Z"; ++$a; // $a is now "^^A"
$a = "^^Z^^"; ++$a; // $a is now "^^Z^^"

Shell Command Operator

Syntax

shell-command-expression:
   `   dq-char-sequenceopt   `

where ` is the GRAVE ACCENT character 0x60, commonly referred to as a backtick.

Semantics

This operator passes dq-char-sequence to the command shell for execution, as though it was being passed to the library function shell_exec. If the output from execution of that command is written to STDOUT, that output is the result of this operator as a string. If the output is redirected away from STDOUT, or dq-char-sequence is empty or contains only white space, the result of the operator is NULL.

If shell_exec is disabled, this operator is disabled.

Examples

$result = `ls`;           // result is the output of command ls
$result = `ls >dirlist.txt`;  // result is NULL
$d = "dir"; $f = "*.*";
$result = `$d {$f}`;      // result is the output of command dir *.*

Scope-Resolution Operator

Syntax

scoped-property-access-expression:
   scope-resolution-qualifier   ::   simple-variable

scoped-call-expression:
   scope-resolution-qualifier   ::   member-name   (   argument-expression-listopt   )
   scope-resolution-qualifier   ::   member-name   (   argument-expression-list   ,   )

class-constant-access-expression:
   scope-resolution-qualifier   ::   name

scope-resolution-qualifier:
   relative-scope
   qualified-name
   dereferencable-expression

relative-scope:
   self
   parent
   static

Constraints

qualified-name must be the name of a class or interface type.

dereferencable-expression must be a value of type string, which contains the name of a class or interface type, or an object.

Semantics

From inside or outside a class or interface, operator :: allows the selection of a constant. From inside or outside a class, this operator allows the selection of a static property, static method, or instance method. From within a class, it also allows the selection of an overridden property or method.

If the scoped-property-access-expression form is used, this operator is accessing a static property given by simple-variable and can be used as an lvalue.

If the class-constant-access-expression form is used, this operator is is accessing a class constant given by name. This form can not be used as an lvalue.

If the scoped-call-expression form is used, the operator is calling the method given by member-anem, which, outside of the object context, is treated as static method call.

Inside of the object context when $this is defined and the called method is not static and the called class is the same as a parent of the class of $this, then the method call is non-static with the same $this. Otherwise it is a static method call.

relative-scope designates the class with relation to the current class scope. From within a class, self refers to the same class, parent refers to the class the current class extends from. From within a method, static refers to the class corresponds to the class inheritance context in which the method is called. This allows late static binding, when class resolution depends on the dynamic call context.

class Base
{
  public function b()
  {
    static::f();  // calls the most appropriate f()
  }
  public function f() { ... }
}
class Derived extends Base
{
  public function f() { ... }
}
$b1 = new Base;
$b1->b(); // as $b1 is an instance of Base, Base::b() calls Base::f()
$d1 = new Derived;
$d1->b(); // as $d1 is an instance of Derived, Base::b() calls Derived::f()

The value of the form of scope-resolution-expression ending in ::class is a string containing the fully qualified name of the current class, which for a static qualifier, means the current class context.

Examples

final class MathLibrary
{
  public static function sin() { ... }
  ...
}
$v = MathLibrary::sin(2.34);  // call directly by class name
$clName = 'MathLibrary';
$v = $clName::sin(2.34);    // call indirectly via string
// -----------------------------------------
class MyRangeException extends Exception
{
  public function __construct($message, ...)
  {
    parent::__construct($message);
    ...
  }
  ...
}
// -----------------------------------------
class Point
{
  private static $pointCount = 0;
  public static function getPointCount()
  {
    return self::$pointCount;
  }
  ...
}

The clone Operator

Syntax

clone-expression:
   primary-expression
   clone   primary-expression

Constraints

primary-expression must designate an object.

Semantics

The clone operator creates a new object that is a shallow copy of the object designated by primary-expression. Then, if the class type of primary-expression has a method called __clone, it is called to perform a deep copy. The result is the new object.

Examples

Consider a class Employee, from which is derived a class Manager. Let us assume that both classes contain properties that are objects. clone is used to make a copy of a Manager object, and behind the scenes, the Manager object uses clone to copy the properties for the base class, Employee.

class Employee
{
  //...
  public function __clone()
  {
    // make a deep copy of Employee object
  }
}
class Manager extends Employee
{
  //...
  public function __clone()
  {
    $v = parent::__clone();
    // make a deep copy of Manager object

  }
}
$obj1 = new Manager("Smith", 23);
$obj2 = clone $obj1;  // creates a new Manager that is a deep copy

Exponentiation Operator

Syntax

exponentiation-expression:
   clone-expression
   clone-expression   **   exponentiation-expression

Semantics

The ** operator produces the result of raising the value of the left-hand operand to the power of the right-hand one.

If either of the operands have an object type supporting ** operation, then the object semantics defines the result. The left operand is checked first.

If either or both operands have non-numeric types, their values are converted to type int or float, as appropriate. If both operands have non-negative integer values and the result can be represented as an int, the result has type int; otherwise, the result has type float. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error must be produced for each.

Examples

2**3;   // int with value 8
2**3.0;   // float with value 8.0
"2.0"**"3"; // float with value 8.0

Unary Operators

General

Syntax

unary-expression:
   exponentiation-expression
   unary-op-expression
   error-control-expression
   cast-expression

Semantics

These operators associate right-to-left.

Unary Arithmetic Operators

Syntax

unary-op-expression:
   unary-operator   unary-expression

unary-operator: one of
   +   -   ~

Constraints

The operand of the unary + and unary - must have scalar-compatible type.

The operand of the unary ~ operator must have arithmetic or string type, or be an object supporting ~.

Semantics

Arithmetic Operands

For a unary + operator used with an arithmetic operand, the type and value of the result is the type and value of the operand.

For a unary - operator used with an arithmetic operand, the value of the result is the negated value of the operand. However, if an int operand’s original value is the smallest representable for that type, the operand is treated as if it were float and the result will be float.

For a unary ~ operator used with an int operand, the type of the result is int. The value of the result is the bitwise complement of the value of the operand (that is, each bit in the result is set if and only if the corresponding bit in the operand is clear). For a unary ~ operator used with a float operand, the value of the operand is first converted to int before the bitwise complement is computed.

Boolean Operands

For a unary + operator used with a TRUE-valued operand, the value of the result is 1 and the type is int. When used with a FALSE-valued operand, the value of the result is zero and the type is int.

For a unary - operator used with a TRUE-valued operand, the value of the result is -1 and the type is int. When used with a FALSE-valued operand, the value of the result is zero and the type is int.

NULL-valued Operands

For a unary + or unary - operator used with a NULL-valued operand, the value of the result is zero and the type is int.

String Operands

For a unary + or - operator used with a numeric string or a leading-numeric string, the string is first converted to an int or float, as appropriate, after which it is handled as an arithmetic operand. The trailing non-numeric characters in leading-numeric strings are ignored. With a non-numeric string, the result has type int and value 0. If the string was leading-numeric or non-numeric, a non-fatal error MUST be produced.

For a unary ~ operator used with a string, the result is the string with each byte being bitwise complement of the corresponding byte of the source string.

Object Operands

If the operand has an object type supporting the operation, then the object semantics defines the result. Otherwise, for ~ the fatal error is issued and for + and - the object is converted to int.

Examples

$v = +10;
if ($v1 > -5) // ...
$v = ~0b1010101;
$s = "\x86\x97"; $s = ~$s; // $s is "yh"

Error Control Operator

Syntax

error-control-expression:
   @   unary-expression

Semantics

Operator @ suppresses the reporting of any error messages generated by the evaluation of unary-expression.

If a custom error-handler has been established using the library function set_error_handler, that handler is still called.

Examples

$infile = @fopen("NoSuchFile.txt", 'r');

On open failure, the value returned by fopen is FALSE, which is sufficient to know to handle the error. The error message that may have been generated by the fopen call is suppressed (not displayed and not logged).

Implementation Notes

Given the following example:

function f() {
  $ret = $y;
  return $ret;
}

$x = @f();  // without @, get "Undefined variable: y"

The following code shows how this statement is handled:

$origER = error_reporting();
error_reporting(0);
$tmp = f();
$curER = error_reporting();
if ($curER === 0) error_reporting($origER);
$x = $tmp;

Cast Operator

Syntax

cast-expression:
   (   cast-type   )   unary-expression

cast-type: one of
   array   binary   bool   boolean   double   int   integer   float   object
   real   string   unset

Constaints

A cast-type of unset is no longer supported and results in a compile-time error.

Semantics

With the exception of the cast-type unset and binary (see below), the value of the operand cast-expression is converted to the type specified by cast-type, and that is the type and value of the result. This construct is referred to as a cast and is used as the verb, “to cast”. If no conversion is involved, the type and value of the result are the same as those of cast-expression.

A cast can result in a loss of information.

A cast-type of array results in a conversion to type array.

A cast-type of binary is reserved for future use in dealing with so-called binary strings. For now, it is fully equivalent to string cast.

A cast-type of bool or boolean results in a conversion to type bool.

A cast-type of int or integer results in a conversion to type int.

A cast-type of float, double, or real results in a conversion to type float.

A cast-type of object results in a conversion to type object.

A cast-type of string results in a conversion to type string.

Examples

(int)(10/3)          // results in the int 3 rather than the float 3.333...
(array)(16.5)      // results in an array of 1 float; [0] = 16.5
(int)(float)"123.87E3" // results in the int 123870

instanceof Operator

Syntax

instanceof-expression:
   unary-expression
   instanceof-subject   instanceof   class-type-designator

instanceof-subject:
   instanceof-expression

Semantics

Operator instanceof returns TRUE if the value designated by instanceof-subject is an object having the type specified by class-type-designator, is an object whose type is derived from that type, or is an object whose type implements the interface specified by class-type-designator. Otherwise, it returns FALSE.

The type can be specified by class-type-designator in one of the three forms:

  1. qualified-name specifies the type name directly.
  2. When the new-variable form is used, new-variable may have a string value that contains a class or interface name.
  3. Alternatively, new-variable can designate an object, in which case the type of the object is used as the specified type. Note that an interface can not be specified with this form.

Note that instanceof will not invoke autoloader if the name of the type given does not correspond to the existing class or interface, instead it will return FALSE.

Examples

class C1 {  }
$c1 = new C1;
class C2 {  }
$c2 = new C2;
class D extends C1 { };
$d = new D;
var_dump($d instanceof C1);      // TRUE
var_dump($d instanceof C2);      // FALSE
var_dump($d instanceof D);       // TRUE
// -----------------------------------------
interface I1 { }
interface I2 { }
class E1 implements I1, I2 { }
$e1 = new E1;
var_dump($e1 instanceof I1);       // TRUE
$iName = "I2";
var_dump($e1 instanceof $iName);   // TRUE
$e2 = new E1;
var_dump($e2 instanceof $e1);      // TRUE

Logical NOT Operator

logical-NOT-expression:
   instanceof-expression
   !   instanceof-expression

Semantics

The value of the operand is converted to type bool and if it is TRUE then the result of the operator is FALSE. The result is TRUE otherwise.

Examples

$t = TRUE;
if (!$t) // ...

Multiplicative Operators

Syntax

multiplicative-expression:
   logical-NOT-expression
   multiplicative-expression   *   logical-NOT-expression
   multiplicative-expression   /   logical-NOT-expression
   multiplicative-expression   %   logical-NOT-expression

Constraints

The right-hand operand of operator / and operator % must not be zero.

Semantics

If either of the operands is an object supporting the operation, the result is defined by that object’s semantics, with the left operand checked first.

The binary * operator produces the product of its operands. If either or both operands have non-numeric types, their values are converted to type int or float, as appropriate. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each. Then if either operand has type float, the other is converted to that type, and the result has type float. Otherwise, both operands have type int, in which case, if the resulting value can be represented in type int that is the result type. Otherwise, the result would have type float.

Division by zero results in a non-fatal error. If the value of the numerator is positive, the result value is INF. If the value of the numerator is negative, the result value is -INF. If the value of the numerator is zero, the result value is NAN.

The binary / operator produces the quotient from dividing the left-hand operand by the right-hand one. If either or both operands have non-numeric types, their values are converted to type int or float, as appropriate. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error must be produced for each. Then if either operand has type float, the other is converted to that type, and the result has type float. Otherwise, both operands have type int, in which case, if the mathematical value of the computation can be preserved using type int, that is the result type; otherwise, the type of the result is float.

The binary % operator produces the remainder from dividing the left-hand operand by the right-hand one. If the type of both operands is not int, their values are converted to that type. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each. The result has type int. If the right-hand operand has value zero, an exception of type DivisionByZeroError is thrown.

These operators associate left-to-right.

Examples

-10 * 100;       // int with value -1000
100 * -3.4e10;   // float with value -3400000000000
"123" * "2e+5;   // float with value 24600000
100 / 100;       // int with value 1
100  / "123";    // float with value 0.8130081300813
"123" % 100;     // int with value 23
100 / 0;         // results in a diagnostic followed by bool with value false
100 / 0.0;       // results in a diagnostic followed by bool with value false
1.3 / 0;         // results in a diagnostic followed by bool with value false
1.3 / 0.0;       // results in a diagnostic followed by bool with value false
100 / "a";       // results in a diagnostic followed by bool with value false (a is converted to 0)

Additive Operators

Syntax

additive-expression:
   multiplicative-expression
   additive-expression   +   multiplicative-expression
   additive-expression   -   multiplicative-expression
   additive-expression   .   multiplicative-expression

Constraints

If either operand of + has array type, the other operand must also have array type.

Binary - operator can not be applied to arrays.

Semantics

If either of the operands is an object supporting the operation, the result is defined by that object’s semantics, with the left operand checked first.

For non-array operands, the binary + operator produces the sum of those operands, while the binary - operator produces the difference of its operands when subtracting the right-hand operand from the left-hand one. If either or both operands have non-array, non-numeric types, their values are converted to type int or float, as appropriate. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each. Then if either operand has type float, the other is converted to that type, and the result has type float. Otherwise, both operands have type int, in which case, if the resulting value can be represented in type int that is the result type. Otherwise, the result would have type float.

If both operands have array type, the binary + operator produces a new array that is the union of the two operands. The result is a copy of the left-hand array with elements inserted at its end, in order, for each element in the right-hand array whose key does not already exist in the left-hand array. Any element in the right-hand array whose key exists in the left-hand array is ignored.

The binary . operator creates a string that is the concatenation of the left-hand operand and the right-hand operand, in that order. If either or both operands have types other than string, their values are converted to type string. The result has type string.

These operators associate left-to-right.

Examples

-10 + 100;        // int with value 90
100 + -3.4e10;    // float with value -33999999900
"123" + "2e+5";   // float with value 200123
100 - "123";      // int with value 23
-3.4e10 - "abc";  // float with value -34000000000
// -----------------------------------------
[1, 5 => FALSE, "red"] + [4 => -5, 1.23]; // [1, 5 => FALSE, "red", 4 => -5]
  // dupe key 5 (value 1.23) is ignored
[NULL] + [1, 5 => FALSE, "red"];          // [NULL, 5 => FALSE, "red"]
  // dupe key 0 (value 1) is ignored
[4 => -5, 1.23] + [NULL];                 // [4 => -5, 1.23, 0 => NULL]
// -----------------------------------------
-10 . NAN;        // string with value "-10NAN"
INF . "2e+5";     // string with value "INF2e+5"
TRUE . NULL;      // string with value "1"
10 + 5 . 12 . 100 - 50;  // int with value 1512050; ((((10 + 5).12).100)-50)

Bitwise Shift Operators

Syntax

shift-expression:
   additive-expression
   shift-expression   <<   additive-expression
   shift-expression   >>   additive-expression

Constraints

Each of the operands must have scalar-compatible type.

Semantics

If either of the operands is an object supporting the operation, the result is defined by that object’s semantics, with the left operand checked first.

Given the expression e1 << e2, the bits in the value of e1 are shifted left by e2 positions. Bits shifted off the left end are discarded, and zero bits are shifted on from the right end. Given the expression e1 >> e2, the bits in the value of e1 are shifted right by e2 positions. Bits shifted off the right end are discarded, and the sign bit is propagated from the left end.

If either operand does not have type int, its value is first converted to that type. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each.

The type of the result is int, and the value of the result is that after the shifting is complete. The values of e1 and e2 are unchanged.

Left shifts where the shift count is greater than the bit width of the integer type (e.g. 32 or 64) must always result in 0, even if there is no native processor support for this.

Right shifts where the shift count is greater than the bit width of the integer type (e.g. 32 or 64) must always result in 0 when e1 is positive and -1 when e1 is negative, even if there is no native processor support for this.

If the shift count is negative, an exception of type ArithmeticError is thrown.

These operators associate left-to-right.

Examples

1000 >> 2   // 0x3E8 is shifted right 2 places
-1000 << 2  // 0xFFFFFC18 is shifted left 5 places
123 >> 128  // Shift count larger than bit width => result 0
123 << 33   // For 32-bit integers the result is zero, otherwise
            // it is 0x7B shifted left 33 places

Relational Operators

Syntax

relational-expression:
   shift-expression
   relational-expression   <   shift-expression
   relational-expression   >   shift-expression
   relational-expression   <=   shift-expression
   relational-expression   >=   shift-expression
   relational-expression   <=>   shift-expression

Semantics

Operator <=> represents comparison operator between two expressions, with the result being an integer less than 0 if the expression on the left is less than the expression on the right (i.e. if $a < $b would return TRUE), as defined below by the semantics of the operator <, integer 0 if those expressions are equal (as defined by the semantics of the == operator) and integer greater than 0 otherwise.

Operator < represents less-than, operator > represents greater-than, operator <= represents less-than-or-equal-to, and operator >= represents greater-than-or-equal-to.

The type of the result is bool.

Note that greater-than semantics is implemented as the reverse of less-than, i.e. $a > $b is the same as $b < $a. This may lead to confusing results if the operands are not well-ordered - such as comparing two objects not having comparison semantics, or comparing arrays.

The following table shows the result for comparison of different types, with the left operand displayed vertically and the right displayed horizontally. The conversions are performed according to type conversion rules.

NULLboolintfloatstringarrayobjectresource
NULL=->->->->-><<
bool<-1<-<-<-<-<-<-
int<-->22<-<3<-
float<-->22<-<3<-
string<-->->->2, 4<32
array<-->>>>53>
object>->333363
resource>->->->2<32
  • = means the result is always “equals”, i.e. strict comparisons are always FALSE and equality comparisons are always TRUE.
  • < means that the left operand is always less than the right operand.
  • > means that the left operand is always greater than the right operand.
  • -> means that the left operand is converted to the type of the right operand.
  • <- means that the right operand is converted to the type of the left operand.
  • A number means one of the cases below:
  1. If either operand has type bool, the other operand is converted to that type. The result is the logical comparison of the two operands after conversion, where FALSE is defined to be less than TRUE.
  2. If one of the operands has arithmetic type, is a resource, or a numeric string, which can be represented as int or float without loss of precision, the operands are converted to the corresponding arithmetic type, with float taking precedence over int, and resources converting to int. The result is the numerical comparison of the two operands after conversion.
  3. If only one operand has object type, if the object has comparison handler, that handler defines the result. Otherwise, if the object can be converted to the other operand’s type, it is converted and the result is used for the comparison. Otherwise, the object compares greater-than any other operand type.
  4. If both operands are non-numeric strings, the result is the lexical comparison of the two operands. Specifically, the strings are compared byte-by-byte starting with their first byte. If the two bytes compare equal and there are no more bytes in either string, the strings are equal and the comparison ends; otherwise, if this is the final byte in one string, the shorter string compares less-than the longer string and the comparison ends. If the two bytes compare unequal, the string having the lower-valued byte compares less-than the other string, and the comparison ends. If there are more bytes in the strings, the process is repeated for the next pair of bytes.
  5. If both operands have array type, if the arrays have different numbers of elements, the one with the fewer is considered less-than the other one, regardless of the keys and values in each, and the comparison ends. For arrays having the same numbers of elements, the keys from the left operand are considered one by one, if the next key in the left-hand operand exists in the right-hand operand, the corresponding values are compared. If they are unequal, the array containing the lesser value is considered less-than the other one, and the comparison ends; otherwise, the process is repeated with the next element. If the next key in the left-hand operand does not exist in the right-hand operand, the arrays cannot be compared and FALSE is returned. If all the values are equal, then the arrays are considered equal.
  6. When comparing two objects, if any of the object types has its own compare semantics, that would define the result, with the left operand taking precedence. Otherwise, if the objects are of different types, the comparison result is FALSE. If the objects are of the same type, the properties of the objects are compares using the array comparison described above.

These operators associate left-to-right.

Examples

"" < "ab"       // result has value TRUE
"a" > "A"       // result has value TRUE
"a0" < "ab"     // result has value TRUE
"aA <= "abc"    // result has value TRUE
// -----------------------------------------
NULL < [10,2.3] // result has value TRUE
TRUE > -3.4     // result has value FALSE
TRUE < -3.4     // result has value FALSE
TRUE >= -3.4    // result has value TRUE
FALSE < "abc"   // result has value TRUE
// -----------------------------------------
10 <= 0         // result has value FALSE
10 >= "-3.4"    // result has value TRUE
"-5.1" > 0      // result has value FALSE
// -----------------------------------------
[100] < [10,20,30] // result has value TRUE (LHS array is shorter)
[10,20] >= ["red"=>0,"green"=>0] // result has value FALSE, (key 10 does not exists in RHS)
["red"=>0,"green"=>0] >= ["green"=>0,"red"=>0] // result has value TRUE (order is irrelevant)
// ------------------------------------
function order_func($a, $b) {
    return ($a->$x <=> $b->x) ?: ($a->y <=> $b->y) ?: ($a->z <=> $b->z);
}

Equality Operators

Syntax

equality-expression:
   relational-expression
   equality-expression   ==   relational-expression
   equality-expression   !=   relational-expression
   equality-expression   <>   relational-expression
   equality-expression   ===   relational-expression
   equality-expression   !==   relational-expression

Semantics

Operator == represents value equality, operators != and <> are equivalent and represent value inequality.

For operators ==, !=, and <>, the operands of different types are converted and compared according to the same rules as in relational operators. Two objects of different types are always not equal.

Operator === represents same type and value equality, or identity, comparison, and operator !== represents the opposite of ===. The values are considered identical if they have the same type and compare as equal, with the additional conditions below:

  • When comparing two objects, identity operators check to see if the two operands are the exact same object, not two different objects of the same type and value.
  • Arrays must have the same elements in the same order to be considered identical.
  • Strings are identical if they contain the same characters, unlike value comparison operators no conversions are performed for numeric strings.

The type of the result is bool.

These operators associate left-to-right.

Examples

"a" <> "aa" // result has value TRUE
// -----------------------------------------
NULL == 0   // result has value TRUE
NULL === 0  // result has value FALSE
TRUE != 100  // result has value FALSE
TRUE !== 100  // result has value TRUE
// -----------------------------------------
"10" != 10  // result has value FALSE
"10" !== 10 // result has value TRUE
// -----------------------------------------
[10,20] == [10,20.0]  // result has value TRUE
[10,20] === [10,20.0] // result has value FALSE
["red"=>0,"green"=>0] === ["red"=>0,"green"=>0] // result has value TRUE
["red"=>0,"green"=>0] === ["green"=>0,"red"=>0] // result has value FALSE

Bitwise AND Operator

Syntax

bitwise-AND-expression:
   equality-expression
   bitwise-AND-expression   &   equality-expression

Constraints

Each of the operands must have scalar-compatible type.

Semantics

If either of the operands is an object supporting the operation, the result is defined by that object’s semantics, with the left operand checked first.

If either operand does not have type int, its value is first converted to that type. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each.

The result of this operator is the bitwise-AND of the two operands, and the type of that result is int.

However, if both operands are strings, the result is the string composed of the sequence of bytes that are the result of bitwise AND operation performed on the bytes of the operand strings in the matching positions (result[0] = s1[0] & s2[0], etc.). If one of the strings is longer than the other, it is cut to the length of the shorter one.

This operator associates left-to-right.

Examples

0b101111 & 0b101          // 0b101
$lLetter = 0x73;          // letter 's'
$uLetter = $lLetter & ~0x20;  // clear the 6th bit to make letter 'S'

Bitwise Exclusive OR Operator

Syntax

bitwise-exc-OR-expression:
   bitwise-AND-expression
   bitwise-exc-OR-expression   ^   bitwise-AND-expression

Constraints

Each of the operands must have scalar-compatible type.

Semantics

If either of the operands is an object supporting the operation, the result is defined by that object’s semantics, with the left operand checked first.

If either operand does not have type int, its value is first converted to that type. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each.

The result of this operator is the bitwise exclusive-OR of the two operands, and the type of that result is int.

However, if both operands are strings, the result is the string composed of the sequence of bytes that are the result of bitwise XOR operation performed on the bytes of the operand strings in the matching positions (result[0] = s1[0] ^ s2[0], etc.). If one of the strings is longer than the other, it is cut to the length of the shorter one.

This operator associates left-to-right.

Examples

0b101111 ^ 0b101    // 0b101010
$v1 = 1234; $v2 = -987; // swap two integers having different values
$v1 = $v1 ^ $v2;
$v2 = $v1 ^ $v2;
$v1 = $v1 ^ $v2;    // $v1 is now -987, and $v2 is now 1234

Bitwise Inclusive OR Operator

Syntax

bitwise-inc-OR-expression:
   bitwise-exc-OR-expression
   bitwise-inc-OR-expression   |   bitwise-exc-OR-expression

Constraints

Each of the operands must have scalar-compatible type.

Semantics

If either of the operands is an object supporting the operation, the result is defined by that object’s semantics, with the left operand checked first.

If either operand does not have type int, its value is first converted to that type. If either or both operands were leading-numeric or non-numeric strings, a non-fatal error MUST be produced for each.

The result of this operator is the bitwise inclusive-OR of the two operands, and the type of that result is int.

However, if both operands are strings, the result is the string composed of the sequence of bytes that are the result of bitwise OR operation performed on the bytes of the operand strings in the matching positions (result[0] = s1[0] | s2[0], etc.). If one of the strings is shorter than the other, it is extended with zero bytes.

This operator associates left-to-right.

Examples

0b101111 | 0b101      // 0b101111
$uLetter = 0x41;      // letter 'A'
$lLetter = $upCaseLetter | 0x20;  // set the 6th bit to make letter 'a'

Logical AND Operator (form 1)

Syntax

logical-AND-expression-1:
   bitwise-inc-OR-expression
   logical-AND-expression-1   &&   bitwise-inc-OR-expression

Semantics

Given the expression e1 && e2, e1 is evaluated first. If e1 converts to bool as FALSE, e2 is not evaluated, and the result has type bool, value FALSE. Otherwise, e2 is evaluated. If e2 converts to bool as FALSE, the result has type bool, value FALSE; otherwise, it has type bool, value TRUE. There is a sequence point after the evaluation of e1.

This operator associates left-to-right.

Except for the difference in precedence, operator && has exactly the same semantics as operator and.

Examples

if ($month > 1 && $month <= 12) ...

Logical Inclusive OR Operator (form 1)

Syntax

logical-inc-OR-expression-1:
   logical-AND-expression-1
   logical-inc-OR-expression-1   ||   logical-AND-expression-1

Semantics

Given the expression e1 || e2, e1 is evaluated first. If e1 converts to bool as TRUE, e2 is not evaluated, and the result has type bool, value TRUE. Otherwise, e2 is evaluated. If e2 converts to bool as TRUE, the result has type bool, value TRUE; otherwise, it has type bool, value FALSE. There is a sequence point after the evaluation of e1.

This operator associates left-to-right.

Examples

if ($month < 1 || $month > 12) ...

Coalesce Operator

Syntax

coalesce-expression:
   logical-inc-OR-expression-1
   logical-inc-OR-expression-1   ??   coalesce-expression

Semantics

Given the expression e1 ?? e2, if e1 is set and not NULL (i.e. TRUE for isset), then the result is e1. Otherwise, then and only then is e2 evaluated, and the result becomes the result of the whole expression. There is a sequence point after the evaluation of e1.

Note that the semantics of ?? is similar to isset so that uninitialized variables will not produce warnings when used in e1.

This operator associates right-to-left.

Examples

$arr = ["foo" => "bar", "qux" => NULL];
$obj = (object)$arr;

$a = $arr["foo"] ?? "bang"; // "bar" as $arr["foo"] is set and not NULL
$a = $arr["qux"] ?? "bang"; // "bang" as $arr["qux"] is NULL
$a = $arr["bing"] ?? "bang"; // "bang" as $arr["bing"] is not set

$a = $obj->foo ?? "bang"; // "bar" as $obj->foo is set and not NULL
$a = $obj->qux ?? "bang"; // "bang" as $obj->qux is NULL
$a = $obj->bing ?? "bang"; // "bang" as $obj->bing is not set

$a = NULL ?? $arr["bing"] ?? 2; // 2 as NULL is NULL, and $arr["bing"] is not set

function foo() {
    echo "executed!", PHP_EOL;
}
var_dump(true ?? foo()); // outputs bool(true), "executed!" does not appear as it short-circuits

Conditional Operator

Syntax

conditional-expression:
   coalesce-expression
   conditional-expression   ?   expressionopt   :   coalesce-expression

Semantics Given the expression e1 ? e2 : e3, e1 is evaluated first and converted to bool if it has another type. If the result is TRUE, then and only then is e2 evaluated, and the result and its type become the result and type of the whole expression. Otherwise, then and only then is e3 evaluated, and the result and its type become the result and type of the whole expression. There is a sequence point after the evaluation of e1. If e2 is omitted, the result and type of the whole expression is the value and type of e1 (before the conversion to bool).

This operator associates left-to-right.

Examples

for ($i = -5; $i <= 5; ++$i)
  echo "$i is ".(($i & 1 == TRUE) ? "odd\n" : "even\n");
// -----------------------------------------
$a = 10 ? : "Hello";  // result is int with value 10
$a = 0 ? : "Hello";     // result is string with value "Hello"
$i = PHP_INT_MAX;
$a = $i++ ? : "red";  // result is int with value 2147483647 (on a 32-bit
                // system) even though $i is now the float 2147483648.0
// -----------------------------------------
$i++ ? f($i) : f(++$i); // the sequence point makes this well-defined
// -----------------------------------------
function factorial($int)
{
  return ($int > 1) ? $int * factorial($int - 1) : $int;
}

Assignment Operators

General

Syntax

assignment-expression:
   conditional-expression
   simple-assignment-expression
   compound-assignment-expression

Constraints

The left-hand operand of an assignment operator must be a modifiable lvalue.

Semantics

These operators associate right-to-left.

Simple Assignment

Syntax

simple-assignment-expression:
   variable   =   assignment-expression
   list-intrinsic   =   assignment-expression

Constraints

If the location designated by the left-hand operand is a string element, the key must not be a negative-valued int, and the right-hand operand must have type string.

Semantics

If assignment-expression designates an expression having value type, see assignment for scalar types If assignment-expression designates an expression having handle type, see assignment for object and resource types. If assignment-expression designates an expression having array type, see assignment of array types.

The type and value of the result is the type and value of the left-hand operand after the store (if any [see below]) has taken place. The result is not an lvalue.

If the location designated by the left-hand operand is a non-existent array element, a new element is inserted with the designated key and with a value being that of the right-hand operand.

If the location designated by the left-hand operand is a string element, then if the key is a negative-valued int, there is no side effect. Otherwise, if the key is a non-negative-valued int, the left-most single character from the right-hand operand is stored at the designated location; all other characters in the right-hand operand string are ignored. If the designated location is beyond the end of the destination string, that string is extended to the new length with spaces (0x20) added as padding beyond the old end and before the newly added character. If the right-hand operand is an empty string, the null character \0 (0x00) is stored.

Examples

$a = $b = 10    // equivalent to $a = ($b = 10)
$v = array(10, 20, 30);
$v[1] = 1.234;    // change the value (and type) of an existing element
$v[-10] = 19;   // insert a new element with int key -10
$v["red"] = TRUE; // insert a new element with string key "red"
$s = "red";
$s[1] = "X";    // OK; "e" -> "X"
$s[-5] = "Y";   // warning; string unchanged
$s[5] = "Z";    // extends string with "Z", padding with spaces in [3]-[5]
$s = "red";
$s[0] = "DEF";    // "r" -> "D"; only 1 char changed; "EF" ignored
$s[0] = "";       // "D" -> "\0"
$s["zz"] = "Q";   // warning; defaults to [0], and "Q" is stored there
// -----------------------------------------
class C { ... }
$a = new C; // make $a point to the allocated object

list intrinsic

Syntax

list-intrinsic:
   list   (   list-expression-list   )

list-expression-list:
   unkeyed-list-expression-list
   keyed-list-expression-list   ,opt

unkeyed-list-expression-list:
   list-or-variable
   ,
   unkeyed-list-expression-list   ,   list-or-variableopt

keyed-list-expression-list:
   expression   =>   list-or-variable
   keyed-list-expression-list   ,   expression   =>   list-or-variable

list-or-variable:
   list-intrinsic
   &opt   variable

Constraints

list-intrinsic must be used as the left-hand operand in a simple-assignment-expression of which the right-hand operand must be an expression that designates an array or object implementing the ArrayAccess interface (called the source array).

Each variable in list-or-variable must designate a writable variable (called the target variable).

At least one of the elements of the list-expression-list must be non-empty.

Semantics

This intrinsic assigns one or more elements of the source array to the target variables. Target variables may be assigned by reference. On success, it will return a copy of the source array. If the source array is not an array or object implementing ArrayAccess no assignments are performed and the return value is NULL.

For unkeyed-list-expression-list, all elements in the source array having keys of type string are ignored. The element having an int key of 0 is assigned to the first target variable, the element having an int key of 1 is assigned to the second target variable, and so on, until all target variables have been assigned. Any other array elements are ignored. If there are fewer source array elements having int keys than there are target variables, the unassigned target variables are set to NULL and a non-fatal error is produced.

For keyed-list-expression-list, each key-variable pair is handled in turn, with the key and variable being separated by the => symbol. The element having the first key, with the key having been converted using the same rules as the subscript operator, is assigned to the frst target variable. This process is repeated for the second => pair, if any, and so on. Any other array elements are ignored. If there is no array element with a given key, the unassigned target variable is set to NULL and a non-fatal error is produced.

The assignments must occur in this order.

Any target variable may be a list, in which case, the corresponding element is expected to be an array.

If the source array elements and the target variables overlap in any way, the behavior is unspecified.

Examples

list($min, $max, $avg) = array(0, 100, 67);
  // $min is 0, $max is 100, $avg is 67
list($min, $max, $avg) = array(2 => 67, 1 => 100, 0 => 0);
  // same as example above
list($min, , $avg) = array(0, 100, 67);
  // $min is 0, $avg is 67
list($min, $max, $avg) = array(0, 2 => 100, 4 => 67);
  // $min is 0, $max is NULL, $avg is 100
list($min, list($max, $avg)) = [0, [1 => 67, 99, 0 => 100], 33];
  // $min is 0, $max is 100, $avg is 67

list($arr[1], $arr[0]) = [0, 1];
  // $arr is [1 => 0, 0 => 1], in this order
list($arr2[], $arr2[]) = [0, 1];
  // $arr2 is [0, 1]

$a = [1, 2];
list(&$one, $two) = $a;
  // $a[0] is 1, $a[1] is 2
$one++;
  // $a[0] is 2, $a[1] is 2

list("one" => $one, "two" => $two) = ["one" => 1, "two" => 2];
  // $one is 1, $two is 2
list(
    "one" => $one,
    "two" => $two,
) = [
    "one" => 1,
    "two" => 2,
];
  // $one is 1, $two is 2

$a = ['one' => 1, 'two' => 2];
list('one' => &$one, 'two' => $two) = $a;
  // $a['one'] is 1, $a['two'] is 2
$one++;
  // $a['one'] is 2, $a['two'] is 2

list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = [
    ["x" => 1, "y" => 2],
    ["x" => 3, "y" => 4]
];
  // $x1 is 1, $y1 is 2, $x2 is 3, $y2 is 4
list(0 => list($x1, $x2), 1 => list($x2, $y2)) = [[1, 2], [3, 4]];
  // $x1 is 1, $y1 is 2, $x2 is 3, $y2 is 4

byRef Assignment

Syntax

byref-assignment-expression:
   variable   =   &   variable

Constraints

The right-hand-side variable must be an lvalue or a call to a function that returns a value byRef.

Semantics

unary-expression becomes an alias for assignment-expression. If assignment-expression designates an expression having value type, see byRef assignment for scalar types If assignment-expression designates an expression having handle type, see byRef assignment for non-scalar types. If assignment-expression designates an expression having array type, see deferred array copying.

Examples

$a = 10;
$b =& $a;   // make $b an alias of $a
++$a;       // increment $a/$b to 11
$b = -12;   // sets $a/$b to -12
$a = "abc";     // sets $a/$b to "abc"
unset($b);      // removes $b's alias to $a
// -----------------------------------------
function &g2() { $t = "xxx"; return $t; } // return byRef
$b =& g2();     // make $b an alias to "xxx"

Compound Assignment

Syntax

compound-assignment-expression:
   variable   compound-assignment-operator   assignment-expression

compound-assignment-operator: one of
   **=   *=   /=   %=   +=   -=   .=   <<=   >>=   &=   ^=   |=

Constraints

Any constraints that apply to the corresponding binary operator apply to the compound-assignment form as well.

Semantics

The expression e1 op= e2 is equivalent to e1 = e1 op (e2), except that e1 is evaluated only once.

Examples

$v = 10;
$v += 20;   // $v = 30
$v -= 5;    // $v = 25
$v .= 123.45  // $v = "25123.45"
$a = [100, 200, 300];
$i = 1;
$a[$i++] += 50; // $a[1] = 250, $i → 2

yield Operator

Syntax

yield-from-expression:
   yield from   assignment-expression

yield-expression:
   yield-from-expression
   yield
   yield   yield-expression
   yield   yield-from-expression   =>   yield-expression

Semantics

Any function containing a yield-expression is a generator function. A generator function generates a collection of zero or more key/value pairs where each pair represents the next in some series. For example, a generator might yield random numbers or the series of Fibonacci numbers. When a generator function is called explicitly, it returns an object of type Generator, which implements the interface Iterator. As such, this allows that object to be iterated over using the foreach statement. During each iteration, the Engine calls the generator function implicitly to get the next key/value pair. Then the Engine saves the state of the generator for subsequent key/value pair requests.

The yield operator produces the result NULL unless the method Generator->send was called to provide a result value. This operator has the side effect of generating the next value in the collection.

If the key is omitted from an a yield-expression, an element key of type int is associated with the corresponding value. The key associated is one more than the previously assigned int key for this collection. However, if this is the first element in this collection with an int key, zero is used.

If the value is also omitted, NULL will be used instead.

If the generator function definition declares that it returns byRef, each value in a key/value pair is yielded byRef.

The following applies only to the yield from form:

A generator function (referred to as a delegating generator) can delegate to another generator function (referred to as a subgenerator), a Traversable object, or an array, each of which is designated by expression.

Each value yielded by assignment-expression is passed directly to the delegating generator’s caller.

Each value sent to the delegating generator’s send method is passed to the subgenerator’s send method. If assignment-expression is not a generator function, any sent values are ignored.

Exceptions thrown by assignment-expression are propagated up to the delegating generator.

Upon traversable completion, NULL is returned to the delegating generator if the traversable is not a generator. If the traversable is a generator, its return value is sent to the delegating generator as the value of the yield from expression.

An exception of type Error is thrown if assignment-expression evaluates to a generator that previously terminated with an uncaught exception, or it evaluates to something that is neither Traversable nor an array.

Examples

function getTextFileLines($filename)
{
  $infile = fopen($filename, 'r');
  if ($infile == FALSE) { /* deal with the file-open failure */ }

  try
  {
    while ($textLine = fgets($infile))  // while not EOF
    {
      $textLine = rtrim($textLine, "\r\n"); // strip off terminator
      yield $textLine;
    }
  }
  finally
  {
    fclose($infile);
  }
}
foreach (getTextFileLines("Testfile.txt") as $line) { /* process each line */ }
// -----------------------------------------
function series($start, $end, $keyPrefix = "")
{
  for ($i = $start; $i <= $end; ++$i)
  {
    yield $keyPrefix . $i => $i;  // generate a key/value pair
  }
}
foreach (series(1, 5, "X") as $key => $val) { /* process each key/val pair */ }
// -----------------------------------------
function gen()
{
    yield 1;
    yield from gen2();
    yield 4;
}
function gen2()
{
    yield 2;
    yield 3;
}
foreach (gen() as $val)
{
    echo $val . "\n";   // Produces the values 1, 2, 3, and 4
}
// -----------------------------------------
function g() {
  yield 1;
  yield from [2, 3];
  yield 4;
}
$g = g();
foreach ($g as $yielded) {
    echo $yielded . "\n";   // Produces the values 1, 2, 3, and 4
}

Syntax

print-expression:
   yield-expression
   print   print-expression

Constraints

print-expression value must be convertable to a string. In particular, it should not be an array and if it is an object, it must implement a __toString method.

Semantics

After converting print-expression’s value into a string, if necessary, print writes the resulting string to STDOUT. Unlike echo, print can be used in any context allowing an expression. It always returns the value 1.

See also: double quoted strings and heredoc documents, conversion to string.

Examples

$v1 = TRUE;
$v2 = 123;
print  '>>' . $v1 . '|' . $v2 . "<<\n";   // outputs ">>1|123<<"
print ('>>' . $v1 . '|' . $v2 . "<<\n");  // outputs ">>1|123<<"
$v3 = "qqq{$v2}zzz";
print "$v3\n";            // outputs "qqq123zzz"
$a > $b ? print "..." : print "...";

Logical AND Operator (form 2)

Syntax

logical-AND-expression-2:
   print-expression
   logical-AND-expression-2   and   yield-expression

Semantics

Except for the difference in precedence, operator and has exactly the same semantics as operator &&.

Logical Exclusive OR Operator

Syntax

logical-exc-OR-expression:
   logical-AND-expression-2
   logical-exc-OR-expression   xor   logical-AND-expression-2

Semantics

If either operand does not have type bool, its value is first converted to that type.

Given the expression e1 xor e2, e1 is evaluated first, then e2. If either e1 or e2 converted to bool as TRUE, but not both, the result has type bool, value TRUE. Otherwise, the result has type bool, value FALSE. There is a sequence point after the evaluation of e1.

This operator associates left-to-right.

Examples

f($i++) xor g($i) // the sequence point makes this well-defined

Logical Inclusive OR Operator (form 2)

Syntax

logical-inc-OR-expression-2:
   logical-exc-OR-expression
   logical-inc-OR-expression-2   or   logical-exc-OR-expression

Semantics

Except for the difference in precedence, operator and has exactly the same semantics as operator ||.

Script Inclusion Operators

General

Syntax

expression:
   logical-inc-OR-expression-2
   include-expression
   include-once-expression
   require-expression
   require-once-expression

Semantics

When creating large applications or building component libraries, it is useful to be able to break up the source code into small, manageable pieces each of which performs some specific task, and which can be shared somehow, and tested, maintained, and deployed individually. For example, a programmer might define a series of useful constants and use them in numerous and possibly unrelated applications. Likewise, a set of class definitions can be shared among numerous applications needing to create objects of those types.

An include file is a script that is suitable for inclusion by another script. The script doing the including is the including file, while the one being included is the included file. A script can be an including file and an included file, either, or neither.

Using the series-of-constants example, an include file called Positions.php might define the constants TOP, BOTTOM, LEFT, and RIGHT, in their own namespace, Positions. Using the set-of-classes example, to support two-dimensional geometry applications, an include file called Point.php might define the class Point. An include file called Line.php might define the class Line (where a Line is represented as a pair of Points).An include file, called Circle.php might define the class Circle (where a Circle is represented as a Point for the origin, and a radius).

If a number of the scripts making up an application each use one or more of the Position constants, they can each include the corresponding include file via the include operator. However, most include files behave the same way each time they are included, so it is generally a waste of time including the same include file more than once into the same scope. In the case of the geometry example, any attempt to include the same include file more than once will result in a fatal “attempted class type redefinition” error. However, this can be avoided by using the include_once operator instead.

The require operator is a variant of the include operator, and the require_once operator is a variant of the include_once operator.

It is important to understand that unlike the C/C++ (or similar) preprocessor, script inclusion in PHP is not a text substitution process. That is, the contents of an included file are not treated as if they directly replaced the inclusion operation source in the including file. See examples below for more information.

An inclusion expression can be written to look like a function call; however, that is not the case, even though an included file can return a value to its including file.

The name used to specify an include file may contain an absolute or relative path. In the latter case, an implementation may use the configuration directive include_path to resolve the include file’s location.

Examples:

As mentioned above, script inclusion in PHP is not a text substitution process (unlike C/C++'s preprocessor and alike). This allows that one can specify namespaces in the included file even though nested namespaces in a single file only are not permitted:

include.php

namespace foo;
$x = 'hello';
foo();

index.php

namespace bar {
  include 'include.php'; // this is fine does not result in a nested namespace
  echo $x;               // hello
  \foo\foo();            // function foo is still member of the foo namespace

  //namespace baz{}      // would fail, nesting namespaces are not allowed
}

Moreover, nested classes in a single file are not permitted whereas classes defined in an included file does not result in a nested class (in a conditionally defined class though) - the same applies for nested interfaces or traits:

include.php

namespace foo;
class Foo{}

index.php

class Bar{
  function bar(){
    include 'include.php'; // this is fine, does not result in a nested class
  }
  //class Foo1{}       // would fail, nested classes are not allowed
  //interface Foo2{}   // would fail as well
  //trait Foo3{}       // and would fail as well
}
new Foo();             // fails, \Foo could not be found
new \foo\Foo();        // fails, definition for class Foo was not loaded yet
$bar = new Bar();
$bar->bar();
new Foo();             // still fails, include != use statement
new \foo\Foo();        // succeeds, definition for class Foo was loaded

c-constants can not be defined within a function or method (in contrast to d-constants. As in the other examples above, this is perfectly legal when it happens through a file inclusion in which the constant does not lose its scope. Consider the following example:

include.php

namespace foo;
const X = 2;

index.php

class Bar{
  function bar(){
    include 'include.php';
  }
}
echo X;                // emits a warning: Use of undefined constant X ...
echo \foo\X;           // same as above since the inclusion did not happen yet
$bar = new Bar();
$bar->bar();
echo X;                // still fails, include != use statement
echo \foo\X;           // succeeds, X was defined through the inclusion

In contrast to constants, functions, classes, interfaces and traits, variables defined at the top level of a file might change their meaning (being a global variable) when the corresponding file is included by another file. This is the case when the inclusion happens in a local scope. In this case the variables become local variables of the corresponding scope. Following an example as illustration:

include.php

namespace foo;
$x = 'hello';

index.php

function bar(){
  include 'include.php';  // introduces the local variable $x
  $x = 'hi';              // modification is only local
  return $x;
}
echo bar();               // hi
echo $x;                  // emits a notice: Undefined variable: x ...

include 'include.php';    // introduces the global variable $x
echo $x;                  // hello

The include Operator

Syntax

include-expression:
   include   expression

Constraints

expression must be convertable to a string, which designates a filename.

Semantics

Operator include results in parsing and executing the designated include file. If the filename is invalid or does not specify a readable file, a non-fatal error is produced.

When an included file is opened, parsing begins in HTML mode at the beginning of the file. After the included file has been parsed, it is immediately executed.

Variables defined in an included file take on scope of the source line on which the inclusion occurs in the including file. However, functions and classes defined in the included file are always in global scope.

If inclusion occurs inside a function definition within the including file, the complete contents of the included file are treated as though it were defined inside that function.

The result produced by this operator is one of the following:

  1. If the included file returned any value, that value is the result.
  2. If the included file has not returned any value, the result is the integer 1.
  3. If the inclusion failed for any reason, the result is FALSE.

The library function get_included_files provides the names of all files included by any of the four including operators.

Examples:

$fileName = 'limits' . '.php'; include $fileName;
$inc = include('limits.php');
If ((include 'Positions.php') == 1) ...

The include_once Operator

Syntax

include-once-expression:
   include_once   expression

Semantics

This operator is identical to operator include except that in the case of include_once, the same include file is included once per program execution.

Once an include file has been included, a subsequent use of include_once on that include file results in a return value of TRUE but nothing else happens.

The files are identified by the full pathname, so different forms of the filename (such as full and relative path) still are considered the same file.

Examples:

Point.php:

\\ Point.php:
<?php ...
class Point { ... }

\\ Circle.php:
<?php ...
include_once 'Point.php';
class Circle { /* uses Point somehow */ }

\\ MyApp.php
include_once 'Point.php';   // Point.php included directly
include_once 'Circle.php';    // Point.php now not included indirectly
$p1 = new Point(10, 20);
$c1 = new Circle(9, 7, 2.4);

The require Operator

Syntax

require-expression:
   require   expression

Semantics

This operator is identical to operator include except that in the case of require, failure to find/open the designated include file produces a fatal error.

The require_once Operator

Syntax

require-once-expression:
   require_once   expression

Semantics

This operator is identical to operator require except that in the case of require_once, the include file is included once per program execution.

Once an include file has been included, a subsequent use of require_once on that include file results in a return value of TRUE but nothing else happens.

The files are identified by the full pathname, so different forms of the filename (such as full and relative path) still are considered the same file.

Constant Expressions

Syntax

constant-expression:
   expression

Constraints

The expression may only use the following syntactic elements:

Semantics

A constant-expression evaluates to the value of the constituent expression.

Statements

General

Syntax

statement:
   compound-statement
   named-label-statement
   expression-statement
   selection-statement
   iteration-statement
   jump-statement
   try-statement
   declare-statement
   echo-statement
   unset-statement
   const-declaration
   function-definition
   class-declaration
   interface-declaration
   trait-declaration
   namespace-definition
   namespace-use-declaration
   global-declaration
   function-static-declaration

Compound Statements

Syntax

compound-statement:
   {   statement-listopt   }

statement-list:
   statement
   statement-list   statement

Semantics

A compound statement allows a group of zero or more statements to be treated syntactically as a single statement. A compound statement is often referred to as a block.

Examples

if (condition)
{ // braces are needed as the true path has more than one statement
  // statement-1
  // statement-2
}
else
{ // braces are optional as the false path has only one statement
  // statement-3
}
// -----------------------------------------
while (condition)
{ // the empty block is equivalent to a null statement
}

Labeled Statements

Syntax

named-label-statement:
   name   :

Constraints

Named labels must be unique within a function.

Semantics

A named label can be used as the target of a goto statement. The presence of a label does not by itself alter the flow of execution.

Expression Statements

Syntax

expression-statement:
   expressionopt   ;

Semantics

If present, expression is evaluated for its side effects, if any, and any resulting value is discarded. If expression is omitted, the statement is a null statement, which has no effect on execution.

Examples

$i = 10;  // $i is assigned the value 10; result (10) is discarded
++$i; // $i is incremented; result (11) is discarded
$i++; // $i is incremented; result (11) is discarded
DoIt(); // function DoIt is called; result (return value) is discarded
// -----------------------------------------
$i;   // no side effects, result is discarded. Vacuous but permitted
123;  // likewise for this one and the two statements following
34.5 * 12.6 + 11.987;
TRUE;
// -----------------------------------------
function findValue($table, $value)  // where $table is 2x3 array
{
  for ($row = 0; $row <= 1; ++$row)
  {
    for ($colm = 0; $colm <= 2; ++$colm)
    {
      if ($table[$row][$colm] == $value)
      {
        // ...
        goto done;
      }
    }
  }
  // ...
done:
  ;     // null statement needed as a label must precede a statement
}

Selection Statements

General

Syntax

selection-statement:
   if-statement
   switch-statement

Semantics

Based on the value of a controlling expression, a selection statement selects among a set of statements.

The if Statement

Syntax

if-statement:
   if   (   expression   )   statement   elseif-clauses-1opt   else-clause-1opt
   if   (   expression   )   :   statement-list   elseif-clauses-2opt   else-clause-2opt   endif   ;

elseif-clauses-1:
   elseif-clause-1
   elseif-clauses-1   elseif-clause-1

elseif-clause-1:
   elseif   (   expression   )   statement

else-clause-1:
   else   statement

elseif-clauses-2:
   elseif-clause-2
   elseif-clauses-2   elseif-clause-2

elseif-clause-2:
   elseif   (   expression   )   :   statement-list

else-clause-2:
   else   :   statement-list

Semantics

The two forms of the if statement are equivalent; they simply provide alternate styles.

The result of the controlling expression expression will be converted to type bool if it does not have this type.

If expression is TRUE, the statement that follows immediately is executed. Otherwise, if an elseif clause is present its expression is evaluated in turn, and if it is TRUE, the statement immediately following the elseif is executed. This repeats for every elseif clause in turn. If none of those tests TRUE, if an else clause is present the statement immediately following the else is executed.

An else clause is associated with the lexically nearest preceding if or elseif that is permitted by the syntax.

Examples

if ($count > 0)
{
  ...
  ...
  ...
}
// -----------------------------------------
goto label1;
echo "Unreachable code\n";

if ($a)
{
label1:
  ...
}
else
{
  ...
}
// -----------------------------------------
if (1)
  ...
  if (0)
    ...
else  // this else does NOT go with the outer if
  ...

if (1)
{
  ...
  if (0)
    ...
}
else  // this else does go with the outer if
    ...

The switch Statement

Syntax

switch-statement:
   switch   (   expression   )   {   case-statementsopt   }
   switch   (   expression   )   :   case-statementsopt   endswitch;

case-statements:
   case-statement   case-statementsopt
   default-statement   case-statementsopt

case-statement:
   case   expression   case-default-label-terminator   statement-listopt

default-statement:
   default   case-default-label-terminator   statement-listopt

case-default-label-terminator:
   :
   ;

Constraints

There must be at most one default label.

Semantics

The two forms of the switch statement are equivalent; they simply provide alternate styles.

Based on the value of its expression, a switch statement transfers control to a case label, to a default label, if one exists; or to the statement immediately following the end of the switch statement. A case or default label is only reachable directly within its closest enclosing switch statement.

On entry to the switch statement, the controlling expression is evaluated and then compared with the value of the case label expression values, in lexical order, using the same semantics as ==. If one matches, control transfers to the statement following the corresponding case label. If there is no match, then if there is a default label, control transfers to the statement following that; otherwise, control transfers to the statement immediately following the end of the switch statement. If a switch contains more than one case label whose values compare equal to the controlling expression, the first in lexical order is considered the match.

An arbitrary number of statements can be associated with any case or default label. In the absence of a break statement at the end of a set of such statements, the execution continues into any following statements, ignoring the associated labels. If all cases and the default end in break and there are no duplicate-valued case labels, the order of case and default labels is insignificant.

Case-label values can be runtime expressions, and the types of sibling case-label values need not be the same.

Switches may be nested, in which case, each switch has its own set of switch clauses.

Examples

$v = 10;
switch ($v)
{
default:
  echo "default case: \$v is $v\n";
  break;    // break ends "group" of default statements
case 20:
  echo "case 20\n";
  break;    // break ends "group" of case 20 statements
case 10:
  echo "case 10\n"; // no break, so execution continues to the next label's "group"
case 30:
  echo "case 30\n"; // no break, but then none is really needed either
}
// -----------------------------------------
$v = 30;
switch ($v)
{
case 30.0:  // <===== this case matches with 30
  echo "case 30.0\n";
  break;
default:
  echo "default case: \$v is $v\n";
  break;
case 30:    // <===== rather than this case matching with 30
  echo "case 30\n";
  break;
}
// -----------------------------------------
switch ($v)
{
case 10 + $b: // non-constant expression
  // ...
case $v < $a:   // non-constant expression
  // ...
// ...
}

Iteration Statements

General

Syntax

iteration-statement:
   while-statement
   do-statement
   for-statement
   foreach-statement

The while Statement

Syntax

while-statement:
   while   (   expression   )   statement
   while   (   expression   )   :   statement-list   endwhile   ;

Semantics

The two forms of the while statement are equivalent; they simply provide alternate styles.

The result of the controlling expression expression is converted to type bool if it does not have this type.

If expression tests TRUE, the statement that follows immediately is executed, and the process is repeated. If expression tests FALSE, control transfers to the point immediately following the end of the while statement. The loop body is executed zero or more times.

Examples

$i = 1;
while ($i <= 10):
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
endwhile;
// -----------------------------------------
while (TRUE)
{
  // ...
  if ($done)
    break;  // break out of the while loop
  // ...
}

The do Statement

Syntax

do-statement:
   do   statement   while   (   expression   )   ;

(Note: There is no alternate syntax).

Constraints

The controlling expression expression must have type bool or be implicitly convertible to that type.

Semantics

First, statement is executed and then expression is evaluated.

The result of the controlling expression expression is converted to type bool if it does not have this type.

If the value tests TRUE, the process is repeated. If expression tests FALSE, control transfers to the point immediately following the end of the do statement. The loop body, statement, is executed one or more times.

Examples

$i = 1;
do
{
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
}
while ($i <= 10);

The for Statement

Syntax

for-statement:
   for   (   for-initializeropt   ;   for-controlopt   ;   for-end-of-loopopt   )   statement
   for   (   for-initializeropt   ;   for-controlopt   ;   for-end-of-loopopt   )   :   statement-list   endfor   ;

for-initializer:
   for-expression-group

for-control:
   for-expression-group

for-end-of-loop:
   for-expression-group

for-expression-group:
   expression
   for-expression-group   ,   expression

Note: Unlike C/C++, PHP does not support a comma operator, per se. However, the syntax for the for statement has been extended from that of C/C++ to achieve the same results in this context.

Semantics

The two forms of the for statement are equivalent; they simply provide alternate styles.

The group of expressions in for-initializer is evaluated once, left-to-right, for their side effects. Then the group of expressions in for-control is evaluated left-to-right (with all but the right-most one for their side effects only), with the right-most expression’s value being converted to type bool. If the result is TRUE, statement is executed, and the group of expressions in for-end-of-loop is evaluated left-to-right, for their side effects only. Then the process is repeated starting with for-control. Once the right-most expression in for-control is FALSE, control transfers to the point immediately following the end of the for statement. The loop body, statement, is executed zero or more times.

If for-initializer is omitted, no action is taken at the start of the loop processing. If for-control is omitted, this is treated as if for-control was an expression with the value TRUE. If for-end-of-loop is omitted, no action is taken at the end of each iteration.

Examples

for ($i = 1; $i <= 10; ++$i)
{
  echo "$i\t".($i * $i)."\n"; // output a table of squares
}
// -----------------------------------------
// omit 1st and 3rd expressions

$i = 1;
for (; $i <= 10;):
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
endfor;
// -----------------------------------------
// omit all 3 expressions

$i = 1;
for (;;)
{
  if ($i > 10)
    break;
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
}
// -----------------------------------------
//  use groups of expressions

for ($a = 100, $i = 1; ++$i, $i <= 10; ++$i, $a -= 10)
{
  echo "$i\t$a\n";
}

The foreach Statement

Syntax

foreach-statement:
   foreach   (   foreach-collection-name   as   foreach-keyopt   foreach-value   )   statement
   foreach   (   foreach-collection-name   as   foreach-keyopt   foreach-value   )   :   statement-list   endforeach   ;

foreach-collection-name:
   expression

foreach-key:
   expression   =>

foreach-value:
   &opt   expression
   list-intrinsic

Constraints

The result of the expression foreach-collection-name must be a collection, i.e. either array or object implementing Traversable.

expression in foreach-value and foreach-key should designate a variable.

Semantics

The two forms of the foreach statement are equivalent; they simply provide alternate styles.

The foreach statement iterates over the set of elements in the collection designated by foreach-collection-name, starting at the beginning, executing statement each iteration. On each iteration, if the & is present in foreach-value, the variable designated by the corresponding expression is made an alias to the current element. If the & is omitted, the value of the current element is assigned to the corresponding variable. The loop body, statement, is executed zero or more times. After the loop terminates, the variable designated by expression in foreach-value has the same value as it had after the final iteration, if any.

If foreach-key is present, the variable designated by its expression is assigned the current element’s key value.

In the list-intrinsic case, a value that is an array is split into individual elements.

Examples

$colors = array("red", "white", "blue");
foreach ($colors as $color):
    // ...
endforeach;
// -----------------------------------------
foreach ($colors as $key => $color)
{
    // ...
}
// -----------------------------------------
// Modify the local copy of an element's value

foreach ($colors as $color)
{
  $color = "black";
}
// -----------------------------------------
// Modify the the actual element itself

foreach ($colors as &$color)  // note the &
{
  $color = "black";
}

Jump Statements

General

Syntax

jump-statement:
   goto-statement
   continue-statement
   break-statement
   return-statement
   throw-statement

The goto Statement

Syntax

goto-statement:
   goto   name   ;

Constraints

The name in a goto statement must be that of a named label located somewhere in the current script. Control must not be transferred into or out of a function, or into an iteration statement or a switch statement.

A goto statement must not attempt to transfer control out of a finally-block.

Semantics

A goto statement transfers control unconditionally to the named label.

A goto statement may break out of a construct that is fully contained within a finally-block.

Examples

function findValue($table, $v)  // where $table is 2x3 array
{
  for ($row = 0; $row <= 1; ++$row)
  {
    for ($colm = 0; $colm <= 2; ++$colm)
    {
      if ($table[$row][$colm] == $v)
      {
        echo "$v was found at row $row, column $colm\n";
        goto done; // not quite the same as break 2!
      }
    }
  }
  echo "$v was not found\n";
done:
  ; // note that a label must always precede a statement
}

The continue Statement

Syntax

continue-statement:
   continue   breakout-levelopt   ;

breakout-level:
   integer-literal
   (   breakout-level   )

Constraints

The breakout level must be greater than zero, and it must not exceed the level of actual enclosing iteration and/or switch statements.

A continue statement must not attempt to break out of a finally-block.

Semantics

A continue statement terminates the execution of the innermost enclosing iteration or switch statement. breakout-level specifies which of these statements is targeted, with innermost being assigned number 1 and containing statements having levels increasing by 1.

A continue statement terminates the execution of one or more enclosing iteration or switch statements, up to the specified level. If the statement at the breakout-level is an iteration statement, the next iteration (if any) of the iteration statement is started. If that statement is a for statement and it has a for-end-of-loop, its end-of-loop expression group for the current iteration is evaluated first. If it is a switch statement, a warning is emitted and the behavior is the same as a break statement at the same breakout-level. If breakout-level is omitted, a level of 1 is assumed.

A continue statement may break out of a construct that is fully contained within a finally-block.

Examples

for ($i = 1; $i <= 5; ++$i)
{
  if (($i % 2) == 0)
    continue;
  echo "$i is odd\n";
}

The break Statement

Syntax

break-statement:
   break   breakout-levelopt   ;

Constraints

The breakout level must be greater than zero, and it must not exceed the level of actual enclosing iteration and/or switch statements.

A break statement must not attempt to break out of a finally-block.

Semantics

A break statement terminates the execution of one or more enclosing iteration or []switch](#the-switch-statement) statements. The number of levels broken out is specified by breakout-level. If breakout-level is omitted, a level of 1 is assumed.

A break statement may break out of a construct that is fully contained within a finally-block.

Examples

$i = 1;
for (;;)
{
  if ($i > 10)
    break;
  // ...
  ++$i;
}
// -----------------------------------------
for ($row = 0; $row <= 1; ++$row)
{
  for ($colm = 0; $colm <= 2; ++$colm)
  {
    if (some-condition-set)
    {
      break 2;
    }
    // ...
  }
}
// -----------------------------------------
for ($i = 10; $i <= 40; $i +=10)
{
        switch($i)
        {
        case 10: /* ... */; break;    // breaks to the end of the switch
        case 20: /* ... */; break 2;  // breaks to the end of the for
        case 30: /* ... */; break;    // breaks to the end of the switch
        }
}

The return Statement

Syntax

return-statement:
   return   expressionopt   ;

Semantics

A return statement from within a function terminates the execution of that function normally, and depending on how the function was defined, it returns the value of expression to the function’s caller by value or byRef. If expression is omitted the value NULL is used.

If execution flows into the closing brace (}) of a function, return NULL; is implied.

Explicit return statements with expression given are not permitted within a function with a void return type and cause a fatal error.

A function may have any number of return statements, whose returned values may have different types.

If an undefined variable is returned byRef, that variable becomes defined, with a value of NULL.

A return statement is permitted in a try-block and a catch-block and in finally-block.

Using a return statement inside a finally-block will override any other return statement or thrown exception from the try-block and all its catch-blocks. Code execution in the parent stack will continue as if the exception was never thrown.

If an uncaught exception exists when a finally-block is executed, if that finally-block executes a return statement, the uncaught exception is discarded.

A return statement may occur in a script outside any function. In an included file, such statement terminates processing of that script file and returns control to the including file. If expression is present, that is the value returned; otherwise, the value NULL is returned. If execution flows to the end of the script, return 1; is implied. However, if execution flows to the end of the top level of a script, return 0; is implied. Likewise, if expression is omitted at the top level. (See also exit).

Returning from a constructor or destructor behaves just like returning from a function.

A return statement inside a generator function causes the generator to terminate.

A generator function can contain a statement of the form return expression ;. The value this returns can be fetched using the method Generator::getReturn, which can only be called once the generator has finishing yielding values. The value cannot be returned byRef.

Return statements can also be used in the body of anonymous functions.

return also terminates the execution of source code given to the intrinsic eval.

Examples

function f() { return 100; }  // f explicitly returns a value
function g() { return; }   // g explicitly returns an implicit NULL
function h() { }      // h implicitly returns NULL
// -----------------------------------------
// j returns one of three dissimilarly-typed values
function j($x)
{
  if ($x > 0)
  {
    return "Positive";
  }
  else if ($x < 0)
  {
    return -1;
  }
  // for zero, implied return NULL
}
function &compute() { ...; return $value; } // returns $value byRef
// -----------------------------------------
class Point
{
  private static $pointCount = 0;
  public static function getPointCount()
  {
    return self::$pointCount;
  }
  ...
}

Implementation Notes

Although expression is a full expression, and there is a sequence point at the end of that expression, a side effect need not be executed if it can be determined that no other program code relies on its having happened. (For example, in the cases of return $a++; and return ++$a;, it is obvious what value must be returned in each case, but if $a is a variable local to the enclosing function, $a need not actually be incremented.

The throw Statement

Syntax

throw-statement:
   throw   expression   ;

Constraints

The type of expression must be Exception or a subclass of that class.

expression must be such that an alias to it can be created.

Semantics

A throw statement throws an exception immediately and unconditionally. Control never reaches the statement immediately following the throw. See exception handling and try-statement for more details of throwing and catching exceptions, and how uncaught exceptions are dealt with.

Rather than handle an exception, a catch-block may (re-)throw the same exception that it caught, or it can throw an exception of a different type.

Examples

throw new Exception;
throw new Exception("Some message", 123);
class MyException extends Exception { ... }
throw new MyException;

The try Statement

Syntax

try-statement:
   try   compound-statement   catch-clauses
   try   compound-statement   finally-clause
   try   compound-statement   catch-clauses   finally-clause

catch-clauses:
   catch-clause
   catch-clauses   catch-clause

catch-clause:
   catch   (   catch-name-list   variable-name   )   compound-statement

catch-name-list:
   qualified-name
   catch-name-list   |   qualified-name

finally-clause:
   finally   compound-statement

Constraints

Each qualified-name inside a catch-name-list must name a type derivated from Exception.

Semantics

In a catch-clause, variable-name designates an exception variable passed in by value. This variable corresponds to a local variable with a scope that extends over the catch-block. During execution of the catch-block, the exception variable represents the exception currently being handled.

Once an exception is thrown, the Engine searches for the nearest catch-block that can handle the exception. The process begins at the current function level with a search for a try-block that lexically encloses the throw point. All catch-blocks associated with that try-block are considered in lexical order. If no catch-block is found that can handle the run-time type of the exception, the function that called the current function is searched for a lexically enclosing try-block that encloses the call to the current function. This process continues until a catch-block is found that can handle the current exception.

The matching is done by considering the classes specified by qualified-name in catch-name-list and comparing it to the type of the exception. If the exception is an instance of one of the specified classes then the clause matches.

If a matching catch-block is located, the Engine prepares to transfer control to the first statement of that catch-block. However, before execution of that catch-block can start, the Engine first executes, in order, any finally-blocks associated with try-blocks nested more deeply than the one that caught the exception.

If no matching catch-block is found, the exception is uncaught and the behavior is implementation-defined.

Examples

function getTextLines($filename)
{
  $infile = fopen($filename, 'r');
  if ($infile == FALSE) { /* deal with an file-open failure */ }
  try
  {
    while ($textLine = fgets($infile))  // while not EOF
    {
      yield $textLine;  // leave line terminator attached
    }
  }
  finally
  {
    fclose($infile);
  }
}
// -----------------------------------------
class DeviceException extends Exception { ... }
class DiskException extends DeviceException { ... }
class RemovableDiskException extends DiskException { ... }
class FloppyDiskException extends RemovableDiskException { ... }

try
{
  process(); // call a function that might generate a disk-related exception
}
catch (FloppyDiskException $fde) { ... }
catch (RemovableDiskException $rde) { ... }
catch (DiskException $de) { ... }
catch (DeviceException $dve) { ... }
finally { ... }

The declare Statement

Syntax

declare-statement:
   declare   (   declare-directive   )   statement
   declare   (   declare-directive   )   :   statement-list   enddeclare   ;
   declare   (   declare-directive   )   ;

declare-directive:
   ticks   =   literal
   encoding   =   literal
   strict_types   =   literal

Constraints

The literal for ticks must designate a value that is, or can be converted, to an integer having a non-negative value.

The literal for encoding must designate a string whose value names an 8-bit-character encoding.

Except for white space, a declare-statement in a script that specifies character-encoding must be the first thing in that script.

The literal for strict_types should be either 0 or 1. Only the statement-less form can be used for strict_types declare. The strict_types declare should be the first statement in the script, excepting other declare statements.

Semantics

The first two forms of the declare statement are equivalent; they simply provide alternate styles.

The declare statement sets an execution directive for its statement body, or for the ;-form, for the remainder of the script or until the statement is overridden by another declare-statement, whichever comes first.

ticks: as the parser is executing, certain statements are considered tickable. For every tick-count ticks, an event occurs, which can be serviced by the function previously registered by the library function register_tick_function. Tick event monitoring can be disabled by calling the library function unregister_tick_function. This facility allows a profiling mechanism to be developed.

encoding: character encoding can be specified on a script-by-script basis using the encoding directive. The joint ISO and IEC standard ISO/IEC 8859 standard series specifies a number of 8-bit-character encodings whose names can be used with this directive. This directive applies only to the file it appears in, and does not affect the included files.

strict_types: if set to 1, scalar type checking for function calls will be checked using strict mode. If set to 0, the coercive mode (default) is used. This directive applies only to the file it appears in, and does not affect the included files.

Examples

declare(ticks = 1) { ... }
declare(encoding = 'ISO-8859-1'); // Latin-1 Western European
declare(encoding = 'ISO-8859-5'); // Latin/Cyrillic

The echo Statement

Syntax

echo-statement:
   echo   expression-list   ;

expression-list:
   expression
   expression-list   ,   expression

Constraints

The expression value must be convertable to a string. In particular, it should not be an array and if it is an object, it must implement a __toString method.

Semantics

After converting each of its expressions’ values to strings, if necessary, echo concatenates them in order given, and writes the resulting string to STDOUT. Unlike print, it does not produce a result.

See also: double quoted strings and heredoc documents, conversion to string.

Examples

$v1 = TRUE;
$v2 = 123;
echo  '>>' . $v1 . '|' . $v2 . "<<\n";    // outputs ">>1|123<<"
echo  '>>' , $v1 , '|' , $v2 , "<<\n";    // outputs ">>1|123<<"
echo ('>>' . $v1 . '|' . $v2 . "<<\n");   // outputs ">>1|123<<"
$v3 = "qqq{$v2}zzz";
echo "$v3\n";

The unset Statement

Syntax

unset-statement:
   unset   (   variable-list   ,opt   )   ;

Semantics

This statement unsets the variables designated by each variable in variable-list. No value is returned. An attempt to unset a non-existent variable (such as a non-existent element in an array) is ignored.

When called from inside a function, this statement behaves, as follows:

  • For a variable declared global in that function, unset removes the alias to that variable from the scope of the current call to that function. The global variable remains set. (To unset the global variable, use unset on the corresponding $GLOBALS array entry.
  • For a variable passed byRef to that function, unset removes the alias to that variable from the scope of the current call to that function. Once the function returns, the passed-in argument variable is still set.
  • For a variable declared static in that function, unset removes the alias to that variable from the scope of the current call to that function. In subsequent calls to that function, the static variable is still set and retains its value from call to call.

Any visible instance property may be unset, in which case, the property is removed from that instance.

If this statement is used with an expression that designates a dynamic property, then if the class of that property has an __unset method, that method is called.

Examples

unset($v);
unset($v1, $v2, $v3);
unset($x->m); // if m is a dynamic property, $x->__unset("m") is called

Arrays

General

An array is a data structure that contains a collection of zero or more elements. An array element can have any type (which allows for arrays of arrays) and the elements of an array need not have the same type. The type of an array element can change over its lifetime. Multidimensional arrays can be implemented as arrays of arrays.

An array is represented as an ordered map in which each entry is a key/value pair that represents an element. An element key can be an expression of type int or string. Duplicate keys are not permitted. The order of the elements in the map is the order in which the elements were inserted into the array. An element is said to exist once it has been inserted into the array with a corresponding key. An array is extended by initializing a previously non-existent element using a new key. Elements can be removed from an array via the unset statement.

The foreach statement can be used to iterate over the collection of elements in an array in order. This statement also provides a way to access the key and value for each element.

Each array has its own current element pointer that designates the current array element. When an array is created, the current element is the first element inserted into the array.

Numerous library functions are available to create and/or manipulate arrays.

Note: Arrays in PHP are different from arrays in several other languages. Specifically, in PHP, array elements need not have the same type, the subscript index need not be an integer, and there is no concept of consecutive elements of the array occupying physically adjacent memory locations).

Array Creation and Initialization

An array is created and initialized using the array-creation operator:

Element Access and Insertion

The value (and possibly the type) of an existing element is changed, and new elements are inserted, using the subscript operator [].

Functions

General

When a function is called, information may be passed to it by the caller via an argument list, which contains one or more argument expressions, or more simply, arguments. These correspond by position to the parameters in a parameter list in the called function’s definition.

An unconditionally defined function is a function whose definition is at the top level of a script. A conditionally defined function is a function whose definition occurs inside a compound statement, such as the body of another function (a nested function), conditional statement, etc. There is no limit on the depth of levels of function nesting. Consider the case of an outer function, and an inner function defined within it. Until the outer function is called at least once, its inner function does not exist. Even if the outer function is called, if its runtime logic bypasses the definition of the inner function, that inner function still does not exist. The conditionally defined function comes into existence when the execution flow reaches the point where the function is defined.

Any function containing yield is a generator function.

Examples

ucf1(); // can call ucf1 before its definition is seen
function ucf1() { ... }
ucf1(); // can call ucf1 after its definition is seen
cf1(); // Error; call to non-existent function
$flag = TRUE;
if ($flag) { function cf1() { ... } } // cf1 now exists
if ($flag) { cf1(); } // can call cf1 now
// -----------------------------------------
function ucf2() { function cf2() { ... } }
cf2(); // Error; call to non-existent function
ucf2(); // now cf2 exists
cf2(); // so we can call it

Function Calls

A function is called via the function-call operator ().

Function Definitions

Syntax

function-definition:
   function-definition-header   compound-statement

function-definition-header:
   function   &opt   name   (   parameter-declaration-listopt   )   return-typeopt

parameter-declaration-list:
   simple-parameter-declaration-list
   variadic-declaration-list

simple-parameter-declaration-list:
   parameter-declaration
   parameter-declaration-list   ,   parameter-declaration

variadic-declaration-list:
   simple-parameter-declaration-list   ,   variadic-parameter
   variadic-parameter

parameter-declaration:
   type-declarationopt   &opt   variable-name   default-argument-specifieropt

variadic-parameter:
   type-declarationopt   &opt   ...   variable-name

return-type:
   :   type-declaration
   :   void

type-declaration:
   ?opt   base-type-declaration

base-type-declaration:
   array
   callable
   iterable
   scalar-type
   qualified-name

scalar-type:
   bool
   float
   int
   string

default-argument-specifier:
   =   constant-expression

Constraints

Each parameter name in a function-definition must be distinct.

A conditionally defined function must exist before any calls are made to that function.

The function-definition for constructors, destructors, and clone methods must not contain return-type.

For generator functions, if the the return type is specified, it can only be one of: Generator, Iterator or Traversable.

Semantics

A function-definition defines a function called name. Function names are not case-sensitive. A function can be defined with zero or more parameters, each of which is specified in its own parameter-declaration in a parameter-declaration-list. Each parameter has a name, variable-name, and optionally, a default-argument-specifier. An & in parameter-declaration indicates that parameter is passed byRef rather than by value. An & before name indicates that the value returned from this function is to be returned byRef. Returning values is described in return statement description.

When the function is called, if there exists a parameter for which there is a corresponding argument, the argument is assigned to the parameter variable using value assignment, while for passing byRef, the argument is assigned to the parameter variable using byRef assignment. If that parameter has no corresponding argument, but the parameter has a default argument value, for passing by value or byRef, the default value is assigned to the parameter variable using value assignment. Otherwise, if the parameter has no corresponding argument and the parameter does not have a default value, the parameter variable is non-existent and no corresponding VSlot exists. After all possible parameters have been assigned initial values or aliased to arguments, the body of the function, compound-statement, is executed. This execution may terminate normally, with return statement or abnormally.

Each parameter is a variable local to the parent function, and is a modifiable lvalue.

A function-definition may exist at the top level of a script, inside any compound-statement, in which case, the function is conditionally defined, or inside a method-declaration section of a class.

If variadic-parameter is defined, every parameter that is supplied to function and is not matched by the preceding parameters is stored in this parameter, as an array element. The first such parameter gets index 0, the next one 1, etc. If no extra parameters is supplied, the value of the parameter is an empty array. Note that if type and/or byRef specifications are supplied to variadic parameter, they apply to every extra parameter captured by it.

By default, a parameter will accept an argument of any type. However, by specifying a type-declaration, the types of argument accepted can be restricted. By specifying array, only an argument of the array type is accepted. By specifying callable, only an argument designating a function (see below) is accepted. By specifying iterable, only an argument that is of type array or an object implementing the Traversable interface is accepted. By specifying qualified-name, only an instance of a class having that type, or being derived from that type, are accepted, or only an instance of a class that implements that interface type directly or indirectly is accepted. The check is the same as for instanceof operator.

callable pseudo-type accepts the following:

  • A string value containing the name of a function defined at the moment of the call.
  • An array value having two elements under indexes 0 and 1. First element can be either string or object. If the first element is a string, the second element must be a string naming a method in a class designated by the first element. If the first element is an object, the second element must be a string naming a method that can be called on an object designated by the first element, from the context of the function being called.
  • An instance of the Closure class.
  • An instance of a class implementing __invoke.

The library function is_callable reports whether the contents of a variable can be called as a function.

Parameters typed with scalar-type are accepted if they pass the type check for this scalar type, as described below. Once the checks have been passed, the parameter types are always of the scalar type specified (or NULL if NULL is allowed).

If a parameter has a type declaration, NULL is not accepted unless the type is nullable. A type is nullable if it is prefixed with ? or if the parameter has a default value that evaluates to NULL.

The default value for a typed parameter must be of the type specified, or NULL, and conversion is not be performed for defaults, regardless of the mode.

Return typing

If the function is defined with return-type declaration, the value returned by the function should be compatible with the defined type, using the same rules as for parameter type checks. NULL values are not allowed for typed returns. If the value of the return statement does not pass the type check, a fatal error is produced.

The void type is a special type that can only be used as a return type, and not in other contexts. It has no effect at runtime, see the return statement.

Type check modes

The type checking can be performed in two modes, strict and coercive (default). The difference between modes exists only for scalar typed parameters (int, float, string and bool).

For coercive mode, if the value passed is of the same type as the parameter, it is accepted. If not, the conversion is attempted. If the conversion succeeds, the converted value is the value assigned to the parameter. If the conversion fails, a fatal error is produced.

For strict mode, the parameter must be exactly of the type that is declared (e.g., string "1" is not accepted as a value for parameter typed as int). The only exception is that int values will be accepted for float typed parameter and converted to float. Note that the strict mode applies not only to user-defined but also to internal functions, please consult the manual for appropriate parameter types. If the types do not match, an exception of type TypeError is thrown.

Note that if the parameter is passed byRef, and conversion happened, then the value will be re-assigned with the newly converted value.

The mode is set by the declare statement.

Note that the type check mode is for the function call controleed by the caller, not the callee. While the check is performed in the function being called, the caller defines whether the check is strict. Same function can be called with both strict and coercive mode checks from different contexts.

The check for the return type is always defined by the script that the function was defined in.

Examples

// coercive mode by default
function accept_int(int $a) { return $a+1; }
accept_int(1); // ok
accept_int("123"); // ok
accept_int("123.34"); // ok
accept_int("123.34 and some"); // ok + notice
accept_int("not 123"); // fatal error!
accept_int(null); // fatal error

function accept_int_or_not(int $a = null) { return $a+1; }
accept_int_or_not(null); // ok

function convert_int(int &$a) { return $a+1; }
$a = "12";
convert_int($a);
var_dump($a); // $a is now int

// Now in strict mode
declare(strict_types=1);
function accept_int(int $a) { return $a+1; }
function accept_float(float $a) { return $a+1; }
accept_int(1); // ok
accept_float(1); // ok
accept_int(1.5); // fatal error
accept_int("123"); // fatal error
echo substr("123", "1"); // fatal error

Variable Functions

If a variable name is followed by the function-call operator (), and the value of that variable designates the function currently defined and visible (see description above), that function will be executed. If the variable does not designate a function or this function can not be called, a fatal error is produced.

Anonymous Functions

An anonymous function, also known as a closure, is a function defined with no name. As such, it must be defined in the context of an expression whose value is used immediately to call that function, or that is saved in a variable for later execution. An anonymous function is defined via the anonymous function creation operator.

For both __FUNCTION__ and __METHOD__, an anonymous function’s name is reported as {closure}.

Classes

General

A class is a type that may contain zero or more explicitly declared members, which can be any combination of class constants; data members, called properties; and function members, called methods. The ability to add properties to an instance at runtime is described in dynamic members section. An object (often called an instance) of a class type is created (i.e., instantiated) via the new operator.

PHP supports inheritance, a means by which a derived class can extend and specialize a single base class (also called parent). Classes in PHP are not all derived from a common ancestor. An abstract class is a base type intended for derivation, but which cannot be instantiated directly. A concrete class is a class that is not abstract. A final class is one from which other classes cannot be derived.

A class may implement one or more interfaces, each of which defines a contract. Interfaces may have method and constants, but not properties.

A class can use one or more traits, which allows a class to have some of the benefits of multiple inheritance.

A constructor is a special method that is used to initialize an instance immediately after it has been created. A destructor is a special method that is used to free resources when an instance is no longer needed. Other special methods exist; they are described in special method section.

The members of a class each have a default or explicitly declared visibility, which determines what source code can access them. A member with private visibility may be accessed only from within its own class. A member with protected visibility may be accessed only from within its own class and from classes above and below it in the inheritance chain. Access to a member with public visibility is unrestricted.

The signature of a method is a combination of that method’s class name, name, and argument list, including argument type declarations and indication for arguments passed byRef, and whether the resulting value is returned byRef.

Methods and properties implemented in a base class can be overridden in a derived class by redeclaring them with the compatible signature (see below). If the overriding method does not have a compatible signature, a non-fatal error is issued but the override is still permitted. It is not recommended to use incompatible signatures for overriding methods.

When an instance is allocated, new returns a handle that points to that object. As such, assignment of a handle does not copy the object itself. (See cloning objects for a discussion of shallow and deep copying).

While PHP supports anonymous class types, such a type cannot be declared using class-declaration. Instead, it must be specified at the time of instantiation; that is, as part of an object-creation-expression.

Class Declarations

Syntax

class-declaration:
   class-modifieropt   class   name   class-base-clauseopt   class-interface-clauseopt   {   class-member-declarationsopt   }

class-modifier:
   abstract
   final

class-base-clause:
   extends   qualified-name

class-interface-clause:
   implements   qualified-name
   class-interface-clause   ,   qualified-name

Constraints

name must be a valid name, and must not be self, parent, or a reserved keyword.

qualified-name must be a valid qualified-name and its name element must not be self, parent, or a reserved keyword.

A class-declaration containing any class-member-declarations that have the modifier abstract must itself have an abstract class-modifier.

class-base-clause must not name a final class.

qualified-name in class-base-clause must name an existing class.

A class must not be derived directly or indirectly from itself.

A concrete class must implement each of the methods from all the interfaces specified in class-interface-clause.

For each interface method, the corresponding implementing method must be compatible with the interface method, including the following:

  • If the interface method is defined as returning byRef, the implementing method should also return byRef.
  • If the interface method is variadic, the implementing method must also be variadic (see also below).
  • The number of required (i.e. having no defaults) arguments of the implementing methods can not be more than the number of required arguments of the interface method (adding non-optional arguments is not allowed).
  • The overall number of arguments for the implementing method should be at least the number of the arguments of the interface method (removing arguments is not allowed).
  • Each argument of the implementing method must be compatible with corresponding argument of the prototype method.
  • If the interface method defines the return type, the implementing method must have the same return type.

Compatible arguments are defined as follows:

  • Parameter names do not matter.
  • If the argument is optional (has default) in the interface, it should be optional in the implementation. However, implementation can provide a different default value.
  • byRef argument requires byRef implementation, and non-byRef argument can not have byRef implementation.
  • For no argument type, only declaration with no type is compatible.
  • For typed argument, only argument with the same type is compatible.
  • For variadic arguments, the definition of the variadic (last) argument should be compatible as per above. The implementation can define additional optional arguments before the variadic argument, but these arguments should be compatible with the variadic argument on the interface method.

qualified-name in class-interface-clause must name an interface type.

Semantics

A class-declaration defines a class type by the name name. Class names are case-insensitive.

The abstract modifier declares a class usable only as a base class; the class cannot be instantiated directly. An abstract class may contain one or more abstract members, but it is not required to do so. When a concrete class is derived from an abstract class, the concrete class must include an implementation for each of the abstract members it inherits. The implementations of abstract methods must have compatible signatures, incompatible implementations are not permitted.

The final modifier prevents a class from being used as a base class.

The optional class-base-clause specifies the one base class from which the class being defined is derived. In such a case, the derived class inherits all the members from the base class.

The optional class-interface-clause specifies the one or more interfaces that are implemented by the class being defined.

Examples

abstract class Vehicle
{
  public abstract function getMaxSpeed();
  ...
}
abstract class Aircraft extends Vehicle
{
  public abstract function getMaxAltitude();
  ...
}
class PassengerJet extends Aircraft
{
  public function getMaxSpeed()
  {
    // implement method
  }
  public function getMaxAltitude()
  {
    // implement method
  }
  ...
}
$pj = new PassengerJet(...);
echo "\$pj's maximum speed: " . $pj->getMaxSpeed() . "\n";
echo "\$pj's maximum altitude: " . $pj->getMaxAltitude() . "\n";
// -----------------------------------------
final class MathLibrary
{
  private function MathLibrary() {} // disallows instantiation
  public static function sin() { ... }
  // ...
}
$v = MathLibrary::sin(2.34);
// -----------------------------------------
interface MyCollection
{
        function put($item);
        function get();
}
class MyList implements MyCollection
{
  public function put($item)
  {
    // implement method
  }
  public function get()
  {
    // implement method
  }
  ...
}

Class Members

Syntax

class-member-declarations:
   class-member-declaration
   class-member-declarations   class-member-declaration

class-member-declaration:
   class-const-declaration
   property-declaration
   method-declaration
   constructor-declaration
   destructor-declaration
   trait-use-clause

Semantics

The members of a class are those specified by its class-member-declarations, and the members inherited from its base class.

A class may contain the following members:

  • Constants – the constant values associated with the class.
  • Properties – the variables of the class.
  • Methods – the computations and actions that can be performed by the class.

Some methods have special semantics, such as:

Members can be imported from one or more traits via trait-use-clauses.

The class can also have dynamic members which are not part of the class definition.

Methods and properties can either be static or instance members. A static member is declared using static. An instance member is one that is not static. The name of a static or instance member can never be used on its own; it must always be used as the right-hand operand of the scope resolution operator or the member access operator.

Each instance of a class contains its own, unique set of instance properties of that class. An instance member is accessed via the -> operator. In contrast, a static property designates exactly one VSlot for its class, which does not belong to any instance, per se. A static property exists whether or not any instances of that class exist. A static member is accessed via the :: operator.

When any instance method operates on a given instance of a class, within that method that object can be accessed via $this. As a static method does not operate on a specific instance, it has no $this.

Examples

class Point
{
  private static $pointCount = 0;     // static property

  private $x;             // instance property
  private $y;             // instance property

  public static function getPointCount()    // static method
  {
    return self::$pointCount;     // access static property
  }
  public function move($x, $y)        // instance method
  {
    $this->x = $x;
    $this->y = $y;
  }
  public function __construct($x = 0, $y = 0) // instance method
  {
    $this->x = $x;          // access instance property
    $this->y = $y;          // access instance property
    ++self::$pointCount;    // access static property
  }
  public function __destruct()      // instance method
  {
    --self::$pointCount;        // access static property
    ...
  }
  ...
}
echo "Point count = " . Point::getPointCount() . "\n";
$cName = 'Point';
echo "Point count = " . $cName::getPointCount() . "\n";

Dynamic Members

Initially, the instance only has properties that are declared explicitly in its class’s definition. However, properties can be added to and removed from the instance at runtime. Static properties of a class can not be changed at runtime, attempt to access non-existing static property results in a fatal error. Runtime-created properties always have public visibility.

The class can also define special methods for dynamic members - methods and properties. This facility uses the same syntax to access the members as the regular members, but instead of accessing actual properties and methods the engine will use special methods to simulate the access.

In the case of dynamic properties, if a class makes provision to do so by defining a series of special methods, it can deal with the allocation and management of storage for those properties, by storing them in another object or in a database, for example. For dynamic methods, both static and non-static methods can be handled by special methods.

Consider the following scenario, which involves dynamic properties:

class Point { ... } // has no public property "color", but has made
                    // provision to support dynamic properties.
$p = new Point(10, 15);
$p->color = "red"; // create/set the dynamic property "color"
$v = $p->color;    // get the dynamic property "color"
isset($p->color);  // test if the dynamic property "color" exists
unset($p->color);  // remove the dynamic property "color"

Dynamic property handling is invoked when a property with specified name name that is not currently visible (because it is hidden or it does not exist). If the property is used in a modifiable lvalue context (as with the assignment of “red”), the Engine generates a call to the instance method __set. This method treats that name as designating a dynamic property of the instance being operated on, and sets its value to “red”, creating the property, if necessary. Similarly, in a non-lvalue context, (as with the assignment of color to $v), the Engine generates a call to the instance method __get, which treats that name as designating a dynamic property of the instance being operated on, and gets its value. In the case of the call to the intrinsic isset, this generates a call to the instance method __isset, while a use of the unset statement generates a call to the instance method __unset. By defining these four special methods, the implementer of a class can control how dynamic properties are handled.

The Engine will call the methods only if they are defined, if they are not defined, no error is produced and default behavior is used.

In the case of a dynamic method, if a call to an undefined instance method is performed and the instance has __call method, then this method is called. Otherwise, as per default, a fatal error is produced. If a static call to an undefined class method is performed, and the class defines a __callStatic method, this method is called. Otherwise, as per default, a fatal error is produced. In both cases, the return value of the call is the return value of the method called.

Consider the following code fragment, in which class Widget has neither an instance method called iMethod nor a static method called sMethod, but that class has made provision to deal with dynamic methods:

$obj = new Widget;
$obj->iMethod(10, TRUE, "abc");
Widget::sMethod(NULL, 1.234);

The call to iMethod is treated as if it were

$obj->__call('iMethod', array(10, TRUE, "abc"))

and the call to sMethod is treated as if it were

Widget::__callStatic('sMethod', array(NULL, 1.234))

Constants

Syntax

const-declaration:
   const   const-elements   ;

class-const-declaration:
   visibility-modifieropt   const   const-elements   ;

const-elements:
   const-element
   const-elements   ,   const-element

const-element:
   name   =   constant-expression

Constraints:

A const-declaration must only appear at the top level of a script, and must not redefine an existing c-constant.

A class-const-declaration must be inside a class-declaration or interface-declaration.

A class constant must not have a static specifier.

Semantics:

A const-declaration defines a c-constant.

If visibility-modifier for a class constant is omitted, public is assumed. The visibility-modifier applies to all constants defined in the const-elements list.

All constants are implicitly static.

Examples:

const MIN_VAL = 20;
const LOWER = MIN_VAL;
// -----------------------------------------
class Automobile
{
  const DEFAULT_COLOR = "white";
  public DEFAULT_BRAND = 'benz';
  protected WHEEL_NUM = 4;
  private PRIVATE_CONST = 'const';
  ...
}
$col = Automobile::DEFAULT_COLOR;

Properties

Syntax

property-declaration:
   property-modifier   property-elements   ;

property-modifier:
   var
   visibility-modifier   static-modifieropt
   static-modifier   visibility-modifieropt

visibility-modifier:
   public
   protected
   private

static-modifier:
   static

property-elements:
   property-element
   property-elements   property-element

property-element:
   variable-name   property-initializeropt   ;

property-initializer:
   =   constant-expression

Semantics

A property-declaration defines one or more instance or static properties.

If visibility-modifier is omitted, public is assumed. The var modifier implies public visibility. The static modifier defines the member as a static member.

The property-initializer for instance properties is applied prior to the class’s constructor being called.

An instance property that is visible may be unset, in which case, the property is actually removed from that instance.

Examples

class Point
{
  private static $pointCount = 0; // static property with initializer

  private $x; // instance property
  private $y; // instance property
  ...

}

Methods

Syntax

method-declaration:
   method-modifiersopt   function-definition
   method-modifiers   function-definition-header   ;

method-modifiers:
   method-modifier
   method-modifiers   method-modifier

method-modifier:
   visibility-modifier
   static-modifier
   class-modifier

Constraints

The method-modifiers preceding a function-definition must not contain the abstract modifier.

The method-modifiers preceding a function-definition-header must contain the abstract modifier.

A method must not have the same modifier specified more than once. A method must not have more than one visibility-modifier. A method must not have both the modifiers abstract and private, or abstract and final.

Semantics

A method-declaration defines an instance or static method. A method is a function that is defined inside a class. However, the presence of abstract indicates an abstract method, in which case, no implementation is provided. The absence of abstract indicates a concrete method, in which case, an implementation is provided.

Method names are case-insensitive.

The presence of final indicates the method cannot be overridden in a derived class.

If visibility-modifier is omitted, public is assumed.

Examples

See class members for examples of instance and static methods. See class declarations for examples of abstract methods and their subsequent definitions.

Constructors

Syntax

constructor-declaration:
   method-modifiers   function   &opt   __construct   (   parameter-declaration-listopt   )   compound-statement

Constraints

An overriding constructor in a derived class must have the same or a less-restricted visibility than the one in the base class.

method-modifiers can not contain static.

Semantics

A constructor is a specially named instance method that is used to initialize an instance immediately after it has been created. Any instance properties having no initializers and not explicitly initialized by a constructor take on the value NULL. A constructor can return a result, by value or byRef. A constructor cannot be abstract or static.

The class does not have to define a constructor.

If visibility-modifier is omitted, public is assumed. A private constructor inhibits the creation of an instance of the class type except by methods of the same class.

Constructors can be overridden in a derived class by redeclaring them. However, an overriding constructor need not have the same or compatible signature as one defined in the base class.

Constructors are called by object-creation-expression and from within other (derived class) constructors.

If classes in a derived-class hierarchy have constructors, it is the responsibility of the constructor at each level to call the constructor in its base-class explicitly, using the notation parent::__construct(...). If a constructor calls its base-class constructor, it is recommended to do so as the first statement in compound-statement, so the object hierarchy is built from the bottom-up. A constructor should not call its base-class constructor more than once. A call to a base-class constructor searches for the nearest constructor in the class hierarchy. Not every level of the hierarchy needs to have a constructor.

Examples

class Point
{
  private static $pointCount = 0;
  private $x;
  private $y;
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
    ++self::$pointCount;
  }
  public function __destruct()
  {
    --self::$pointCount;
    ...
  }
  ...
}
// -----------------------------------------
class MyRangeException extends Exception
{
  public function __construct($message, ...)
  {
    parent::__construct($message);
    ...
  }
  ...
}

Destructors

Syntax

destructor-declaration:
   method-modifiers   function   &opt   __destruct   (   )   compound-statement

Constraints

method-modifiers can not contain static.

Semantics

A destructor is a special-named instance method that is used to free resources when an instance is no longer needed. The destructors for instances of all classes are called automatically once there are no handles pointing to those instances or in some unspecified order during program shutdown. Like any method, a destructor can return a result by value or byRef. A destructor cannot be static.

Destructors are called by the Engine or from within other (derived class) destructors.

If classes in a derived-class hierarchy have destructors, it is the responsibility of the destructor at each level to call the destructor in the base-class explicitly, using the notation parent::__destruct(). If a destructor calls its base-class destructor, it is recommended to do so as the last statement in compound-statement, so the object hierarchy is destructed from the top-down. A destructor should not call its base-class destructor more than once. A call to a base-class destructor searches for the nearest destructor in the class hierarchy. Not every level of the hierarchy need have a destructor. A private destructor inhibits destructor calls from derived classes.

Examples

See constructors section for an example of a constructor and destructor.

Inheritance

When a class extends another class it can override members of the parent class by declaring a member with the same name. Only properties and methods can be overridden.

Visibility of the overridden member can not be made more restrictive, only more permissive (from private to protected to public).

When a private member is overridden, the methods of the defining class still have access to the original private member, however non-static public and protected members are shared across the inheritance chain.

When a method is overridden, the signature of the overriding method should be compatible with the signature of the original method, by the same rule as if the original method belonged to the interface and the overriding method belonged to an implementation. If an implemented method is overridden with an incompatible method, a non-fatal error is issued, however the override is still accepted by the engine. The use of incompatible overrides is not recommended.

Methods with Special Semantics

General

If a class contains a definition for a method having one of the following names, that method must have the prescribed visibility, signature, and semantics:

Method NameDescription
__callCalls a dynamic method in the context of an instance method call.
__callStaticCalls a dynamic method in the context of a static method call.
__cloneTypically used to make a deep copy of an object.
__constructA constructor.
__debugInfoProduce debugging information for the object.
__destructA destructor.
__getRetrieves the value of a given dynamic property.
__invokeCalled when an object is called as a function (e.g. $a()).
__issetReports if a given dynamic property exists.
__setSets the value of a given dynamic property.
__set_stateUsed by export function var_export to restore the state of the object.
__sleepExecuted before serialization of an instance of this class.
__toStringReturns a string representation of the instance on which it is called.
__unsetRemoves a given dynamic property.
__wakeupExecuted after unserialization of an instance of this class.

In general, method names beginning with __ are reserved for special methods. The code should not define methods with names beginning with __ unless it is one of the special methods described here.

Note that while syntax definitions below use the non-abstract syntax in the method definition, the special methods, like any methods, can be declared abstract. In this case the definition does not actually define a special method but defines that an overriding concrete class must declare one. Nevertheless, the constraints on special methods must still be followed in such definitions.

Method __call

Syntax

  method-modifiers function  __call  (  $name  ,  $arguments  )  return-typeopt  compound-statement

Constraints

The method can not be static and must have public visibility.

The arguments passed to this method must not be passed byRef.

Semantics

This instance method is called to invoke the dynamic method designated by $name using the arguments specified by the elements of the array designated by $arguments. It can return any value deemed appropriate.

Typically, __call is called implicitly, when the -> operator is used to call an instance method that is not visible.

While __call can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression p->m(...), where p is an instance and m is an instance-method name. If m is the name of a visible method, p->m(...) does not result in __call’s being called. Instead, the visible method is used. On the other hand, the expression p->__call('m',array(...)) always calls the named dynamic method, ignoring the fact that a visible method having the same name might exist. If m is not the name of a visible method, the two expressions are equivalent; that is; when handling p->m(...), if no visible method by that name is found, a dynamic method is assumed, and __call is called.

While the name source token has a prescribed syntax, there are no restrictions on the content of the dynamic method name designated by $name. Any source character is allowed here.

Examples

class Widget
{
  public function __call($name, $arguments)
  {
    // using the method name and argument list, redirect/process
    // the method call, as desired.
  }
  ...
}
$obj = new Widget;
$obj->iMethod(10, TRUE, "abc"); // $obj->__call('iMethod', array(...))

Method __callStatic

Syntax

  method-modifiers  function  __callStatic  (  $name  ,  $arguments  )  return-typeopt  compound-statement

Constraints

The method-modifiers must contain static and must define public visibility.

The arguments passed to this method must not be passed byRef.

Semantics

This static method is called to invoke the dynamic method designated by $name using the arguments specified by the elements of the array designated by $arguments. It can return any value deemed appropriate.

Typically, __callStatic is called implicitly, when the :: operator is used to call a static method that is not visible.

While __callStatic can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression C::m(...), where C is a class and m is a static-method name. If m is the name of a visible method, C::m(...) does not result in __callStatic’s being called. Instead, the visible method is used. On the other hand, the expression C::__callStatic('m',array(...)) always calls the named dynamic method, ignoring the fact that a static visible method having the same name might exist. If m is not the name of a visible method, the two expressions are equivalent; that is; when handling C::m(...), if no visible method by that name is found, a dynamic method is assumed, and __callStatic is called.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic method name designated by $name. Any source character is allowed here.

Examples

class Widget
{
    public static function __callStatic($name, $arguments)
    {
      // using the method name and argument list, redirect/process\
      // the method call, as desired.
    }
    ...
}

Widget::sMethod(NULL, 1.234); // Widget::__callStatic('sMethod', array(...))

Method __clone

Syntax

  method-modifiers  function  __clone  (  )  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method is called by the clone operator, typically to make a deep copy of the the instance on which it is called. Method __clone cannot be called directly by the program.

Consider a class Employee, from which is derived a class Manager. Let us assume that both classes contain properties that are objects. To make a copy of a Manager object, its __clone method is called to do whatever is necessary to copy the properties for the Manager class. That method should, in turn, call the __clone method of its parent class, Employee, so that the properties of that class can also be copied (and so on, up the derived-class hierarchy).

To clone an object, the clone operator makes a shallow copy of the object on which it is called. Then, if the class of the instance being cloned has a method called __clone, that method is called to make a deep copy. Method __clone cannot be called directly from outside a class; it can only be called by name from within a derived class, using the notation parent::__clone(). This method can return a value; however, if it does so and control returns directly to the point of invocation via the clone operator, that value will be ignored. The value returned to a parent::__clone() call can, however, be retrieved.

While cloning creates a new object, it does so without using a constructor, in which case, code may need to be added to the __clone method to emulate what happens in a corresponding constructor. (See the Point example below).

An implementation of __clone should factor in the possibility of an instance having dynamic properties.

Examples

class Employee
{
  ...
  public function __clone()
  {
    // do what it takes here to make a copy of Employee object properties
  }
}
class Manager extends Employee
{
  ...
  public function __clone()
  {
    parent::__clone(); // request cloning of the Employee properties

    // do what it takes here to make a copy of Manager object properties
  }
  ...
}
// -----------------------------------------
class Point
{
  private static $pointCount = 0;
  public function __construct($x = 0, $y = 0)
  {
    ...
    ++self::$pointCount;
  }
  public function __clone()
  {
    ++self::$pointCount; // emulate the constructor
  }
  ...
}
$p1 = new Point;  // created using the constructor
$p2 = clone $p1;  // created by cloning

Method __debugInfo

Syntax

  method-modifiers function  __debugInfo  (  )   compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

The function should return array.

Semantics

This method allows the class to supply debugging information for the object, which can be used as the source of information for var_dump().

Example

class File {
  // "Resource(stream)" isn't all that useful
  private $fp;

  // But all the stream meta data is
  public function __debugInfo() {
    return $this->fp ? stream_get_meta_data($fp) : [];
  }

  public function open($filename, $mode = 'r'){
    $this->fp = fopen($filename, $mode);
  }
}

$f = new File;
var_dump($f); // object(File)#1 { }
$f->open('http://php.net');
var_dump($f);
/*
object(File)#1 {
  ["wrapper_type"]=>
  string(4) "http"
  ["stream_type"]=>
  string(10) "tcp_socket"
  etc...
*/

Method __get

Syntax

  method-modifiers function  &opt  __get  (  $name  )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method gets the value of the dynamic property designated by $name. It is up to the implementor to define the return value.

Typically, __get is called implicitly, when the -> operator is used in a non-lvalue context and the named property is not visible.

While __get can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression $v = $p->m, where p is an instance and m is a property name. If m is the name of a visible property, p->m does not result in __get’s being called. Instead, the visible property is used. On the other hand, the expression p->__get('m') always gets the value of the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed, and __get is called.

Consider the expression $v = $p->m = 5, where m is a dynamic property. While __set is called to assign the value 5 to that property, __get is not called to retrieve the result after that assignment is complete.

If the implementation wants the caller to be able to modify the contents of the returned value (such as returning an array which can be modified by caller, and the modifications are reflected in the dynamic property), __get should return byRef.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __get($name)
    {
        if (array_key_exists($name, $this->dynamicProperties))
        {
            return $this->dynamicProperties[$name];
        }

        // no-such-property error handling goes here
        return NULL;
    }
  ...
}

Implementation Notes

Consider the following class, which does not contain a property called prop:

class C
{
  public function __get($name)
  {
    return $this->$name;    // must not recurse
  }
  ...
}
$c = new C;
$x = $c->prop;

As no property (dynamic or otherwise) by the name prop exists in the class and a __get method is defined, this looks look a recursive situation. However, the implementation must not allow that. The same applies to seemingly self-referential implementations of __set, __isset, and __unset. Only one iteration of the dynamic resolution is performed per-property, and the special method is called only once per property name.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Method __invoke

Syntax

  method-modifiers  function  __invoke  ( parameter-declaration-listopt  )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method allows an instance to be used with function-call notation. An instance whose class provides this method will also return TRUE when passed to is_callable.

When an instance is called as a function, the argument list used is made available to __invoke, whose return value becomes the return value of the initial function call.

Examples

class C
{
  public function __invoke($p)
  {
    ...
    return ...;
  }
  ...
}
$c = new C;
is_callable($c) // returns TRUE
$r = $c(123);   // becomes $r = $c->__invoke(123);

Method __isset

Syntax

  method-modifiers  function  __isset  (  $name  )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

If the dynamic property designated by $name exists, this instance method returns TRUE; otherwise, FALSE is returned. The speficis of how existence of the dynamic property is determined is left to the implementor of the method.

Typically, __isset is called implicitly, when the intrinsic isset or intrinsic empty is called with an argument that designates a property that is not visible.

While __isset can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression isset($p->m), where p is an instance and m is a property name. If m is the name of a visible property, __isset is not called. Instead, the visible property is used. On the other hand, the expression p->__isset('m') always tests for the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __isset($name)
    {
        return isset($this->dynamicProperties[$name]);
    }
  ...
}

Implementation Notes

See the Implementation Notes for __get.

Method __set

Syntax

  method-modifiers  function  __set  (  $name  ,  $value  )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method sets the value of the dynamic property designated by $name to $value. No value is expected to be returned.

Typically, __set is called implicitly, when the -> operator is used in a modifiable lvalue context and the named property is not visible.

While __set can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression p->m = 5, where p is an instance and m is a property name. If m is the name of a visible property, p->m does not result in __set’s being called. Instead, the visible property is used. On the other hand, the expression p->__set('m',5) always sets the value of the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m, if no visible property by that name is found, a dynamic property is assumed, and __set is called.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __set($name, $value)
    {
        $this->dynamicProperties[$name] = $value;
    }
  ...
}
// -----------------------------------------
class X
{
    public function __destruct() { ... }
}
$p = new Point(5, 9);
$p->thing = new X;  // set dynamic property "thing" to instance with destructor
...
// at the end of the program, p->thing's destructor is called

Implementation Notes

See the Implementation Notes for __get.

Method __set_state

Syntax

  method-modifiers  function  __set_state  ( array  $properties  )  return-typeopt  compound-statement

Constraints

The method-modifiers must contain static and must define public visibility.

Semantics

This function supports the library function var_export when it is given an instance of this class type. var_export takes a variable and produces a string representation of that variable as valid PHP code suitable for use with the intrinsic eval.

For an object, the string returned by var_export has the following general format:

classname::__set_state(array('prop1' => value, ..., 'propN' => value , ))

where the property names prop1 through propN do not include a leading dollar ($). This string contains a call to the __set_state method even if no such method is defined for this class or in any of its base classes, in which case, a subsequent call to eval using this string will produce a fatal error. To allow the string to be used with eval, the method __set_state must be defined, and it must create a new instance of the class type, initialize its instance properties using the key/value pairs in $properties, and it must return that new object.

When extending the class with __set_state method, one should override the method, otherwise a call to it will look for such a method in the base class hierarchy, and that method will return an instance of the associated base class, not of the class on which it was invoked. Usage of static allows late static binding to produce the instance of an appropriate class.

If a derived class defines a __set_state method, but any base class has instance properties that are not visible within that method, that method must invoke parent’s __set_state as well, but that can require support from a base class. See the second example below.

Examples

class Point
{
  private $x;
  private $y;
  static public function __set_state(array $properties)
  {
    $p = new Point;
    $p->x = $properties['x'];
    $p->y = $properties['y'];
    return $p;
  }
  ...
}
$p = new Point(3, 5);
$v = var_export($p, TRUE);  // returns string representation of $p

The string produced looks something like the following:

"Point::__set_state(array(
   'x' => 3,
   'y' => 5,
))"
eval('$z = ' . $v . ";"); // execute the string putting the result in $z
echo "Point \$z is $z\n"; // Point $z is (3,5)
// -----------------------------------------
class B // base class of D
{
  private $bprop;
  public function __construct($p)
  {
    $this->bprop = $p;
  }
  static public function __set_state(array $properties)
  {
    $b = new static($properties['bprop']);  // note the static
    return $b;
    // Because of the "new static", the return statement
    //   returns a B when called in a B context, and
    //   returns a D when called in a D context
  }
}
class D extends B
{
  private $dprop = 123;
  public function __construct($bp, $dp = NULL)
  {
    $this->dprop = $dp;
    parent::__construct($bp);
  }
  static public function __set_state(array $properties)
  {
    $d = parent::__set_state($properties); // expects back a D, NOT a B
    $d->dprop = $properties['dprop'];
    return $d;
  }
}
$b = new B(10);
$v = var_export($b, TRUE);
eval('$z = ' . $v . ";");
var_dump($z);
$d = new D(20, 30);
$v = var_export($d, TRUE);
eval('$z = ' . $v . ";");
var_dump($z);

Method __sleep

Syntax

  method-modifiers  function  __sleep  ( )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

The instance methods __sleep and __wakeup support serialization.

If a class has a __sleep method, the library function serialize calls that method to find out which visible instance properties it should serialize. (In the absence of a __sleep or serialize method, all instance properties are serialized, including ones defined in runtime). This information is returned by __sleep as an array of zero or more elements, where each element’s value is distinct and is the name of a visible instance property. These properties’ values are serialized in the order in which the elements are inserted in the array. If __sleep does not return a value explicitly, NULL is returned, and that value is serialized.

Besides creating the array of property names, __sleep can do whatever else might be needed before serialization occurs.

The alternative to using __sleep and __wakeup is implementing the Serializable interface.

Note that if a class defining __sleep and __wakeup is extended, and the derived class does not override the methods, the serialization and unserialization will be performed as if those were instances of the base class, e.g. additional properties may not be serialized or restored.

Examples

Consider a Point class that not only contains x- and y-coordinates, it also has an id property; that is, each distinct Point created during a program’s execution has a unique numerical id. However, there is no need to include this when a Point is serialized. It can simply be recreated when that Point is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches).

class Point
{
  private static $nextId = 1;
  private $x;
  private $y;
  private $id;
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
    $this->id = self::$nextId++;  // assign the next available id
  }
  public function __sleep()
  {
    return array('y', 'x'); // serialize only $y and $x, in that order
  }
  public function __wakeup()
  {
    $this->id = self::$nextId++;  // assign a new id
  }
  ...
}
$p = new Point(-1, 0);
$s = serialize($p);   // serialize Point(-1,0)
$v = unserialize($s); // unserialize Point(-1,0)

Method __toString

Syntax

  method-modifiers  function  __toString  ( )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

This function must return a string.

This function must not throw any exceptions.

Semantics

This instance method is intended to create a string representation of the instance on which it is called.

__toString is called by a number of language and library facilities, including echo, when an object-to-string conversion is needed. __toString can also be called directly.

An implementation of __toString should factor in the possibility of an instance having dynamic properties.

Examples

class Point
{
  private $x;
  private $y;
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
  }
  public function __toString()
  {
    return '(' . $this->x . ',' . $this->y . ')';
  }
  ...
}
$p1 = new Point(20, 30);
echo $p1 . "\n";  // implicit call to __toString() returns "(20,30)"
// -----------------------------------------
class MyRangeException extends Exception
{
  public function __toString()
  {
    return parent::__toString()
      . string-representation-of-MyRangeException
  }
  ...
}

Method __unset

Syntax

  method-modifiers  function  __unset  (  $name  )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

If the dynamic property designated by $name exists, it is removed by this instance method; otherwise, the call has no effect. No value is expected to be returned.

Typically, __unset is called implicitly, when the unset statement is called with an argument that designates a property that is not visible.

While __unset can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression unset($p->m), where p is an instance and m is a property name. If m is the name of a visible property, __unset is not called. Instead, the visible property is used. On the other hand, the expression p->__unset('m')) always removes the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __unset($name)
    {
        unset($this->dynamicProperties[$name]);
    }
  ...
}

Implementation Notes

See the Implementation Notes for __get.

Method __wakeup

Syntax

  method-modifiers  function  __wakeup  ( )  return-typeopt  compound-statement

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

The instance methods __sleep and __wakeup support serialization.

When the library function unserialize is called on the string representation of an object, as created by the library function serialize, unserialize creates an instance of that object’s type without calling a constructor, and then calls that class’s __wakeup method, if any, to initialize the instance. In the absence of a __wakeup method, all that is done is that the values of the instance properties encoded in the serialized string are restored.

__wakeup is not expected to return a value.

Consider a Point class that not only contains x- and y-coordinates, it also has an id property; that is, each distinct Point created during a program’s execution has a unique numerical id. However, there is no need to include this when a Point is serialized. It can simply be recreated by __wakeup when that Point is unserialized. This means that __wakeup must emulate the constructor, as appropriate.

Examples

See __sleep.

Serialization

In PHP, variables can be converted into some external form suitable for use in file storage or inter-program communication. The process of converting to this form is known as serialization while that of converting back again is known as unserialization. These facilities are provided by the library functions serialize and unserialize, respectively.

In the case of variables that are objects, on their own, these two functions serialize and unserialize all the instance properties, which may be sufficient for some applications. However, if the programmer wants to customize these processes, they can do so in one of two mutually exclusive ways. The first approach is to define methods called __sleep and __wakeup, and have them get control before serialization and after serialization, respectively. For information on this approach, see __sleep and __wakeup. The second approach involves implementing the interface Serializable by defining two methods, serialize and unserialize.

Consider a Point class that not only contains x- and y-coordinates, it also has an id property; that is, each distinct Point created during a program’s execution has a unique numerical id. However, there is no need to include this when a Point is serialized. It can simply be recreated when that Point is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches). Furthermore, consider a class ColoredPoint that extends Point by adding a color property. The following code shows how these classes need be defined in order for both Points and ColoredPoints to be serialized and unserialized:

class Point implements Serializable // note the interface
{
  private static $nextId = 1;
  private $x;
  private $y;
  private $id;  // transient property; not serialized
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
    $this->id = self::$nextId++;
  }
  public function __toString()
  {
    return 'ID:' . $this->id . '(' . $this->x . ',' . $this->y . ')';
  }
  public function serialize()
  {
    return serialize(array('y' => $this->y, 'x' => $this->x));
  }

The custom method serialize calls the library function serialize to create a string version of the array, whose keys are the names of the instance properties to be serialized. The insertion order of the array is the order in which the properties are serialized in the resulting string. The array is returned.

  public function unserialize($data)
  {
    $data = unserialize($data);
    $this->x = $data['x'];
    $this->y = $data['y'];
    $this->id = self::$nextId++;
  }
}

The custom method unserialize converts the serialized string passed to it back into an array. Because a new object is being created, but without any constructor being called, the unserialize method must perform the tasks ordinarily done by a constructor. In this case, that involves assigning the new object a unique id.

$p = new Point(2, 5);
$s = serialize($p);

The call to the library function serialize calls the custom serialize method. Afterwards, the variable $s contains the serialized version of the Point(2,5), and that can be stored in a database or transmitted to a cooperating program. The program that reads or receives that serialized string can convert its contents back into the corresponding variable(s), as follows:

$v = unserialize($s);

The call to the library function unserialize calls the custom unserialize method. Afterwards, the variable $s contains a new Point(2,5).

class ColoredPoint extends Point implements Serializable
{
  const RED = 1;
  const BLUE = 2;

  private $color; // an instance property

  public function __construct($x = 0, $y = 0, $color = RED)
  {
    parent::__construct($x, $y);
    $this->color = $color;
  }

  public function __toString()
  {
    return parent::__toString() . $this->color;
  }

  public function serialize()
  {
    return serialize(array(
      'color' => $this->color,
      'baseData' => parent::serialize()
    ));
  }

As with class Point, this custom method returns an array of the instance properties that are to be serialized. However, in the case of the second element, an arbitrary key name is used, and its value is the serialized version of the base Point within the current ColoredPoint object. The order of the elements is up to the programmer.

    public function unserialize($data)
    {
    $data = unserialize($data);
    $this->color = $data['color'];
    parent::unserialize($data['baseData']);
    }
}

As ColoredPoint has a base class, it unserializes its own instance properties before calling the base class’s custom method, so it can unserialize the Point properties.

$cp = new ColoredPoint(9, 8, ColoredPoint::BLUE);
$s = serialize($cp);
...
$v = unserialize($s);

Function unserialize takes an optional second argument, which specifies an array of trusted class names as strings. Objects found in the data stream whose type name is not in this trusted name list are converted to objects of type __PHP_Incomplete_Class.

Any attempt to serialize an object having an anonymous class type results in an instance of type Exception being thrown.

Predefined Classes

Class Closure

The predefined class Closure is used for representing an anonymous function. It cannot be instantiated except by the Engine, as described below. Closure objects are immutable and must not permit the creation or modification of properties.

Closures can be bound, unbound or static. If a closure is said to be bound, then it has an object that $this will be bound to when called. If a closure is unbound, then it has no object $this will be bound to. If a closure is static, then it cannot be bound.

Closures can be scoped or unscoped. If a closure is said to be scoped, it has a class scope which determines the visibility of the private and protected members of objects of the class, including but not limited to such members on $this. If a closure is said to be unscoped, it has no class scope set.

Closures have an invariant that scoped closures must be bound or static, and unbound closures must be unscoped.

class Closure
{
  public static bind(Closure $closure, $newthis [, $newscope = "static" ]);
  public bindTo($newthis [, $newscope = "static" ]);
  public call($newthis [, ...$parameters ]);
}

The class members are defined below:

NamePurpose
bindDuplicates closure $closure with a specific bound object $newthis and class scope $newscope. If $newthis is NULL then the closure is to be unbound if no scope is specified, or static if a scope is specified. $newscope is the scope the closure is to be given (either a string containing the name of a class, or an object whose class will be used), or "static" to keep the current one. Returns a new Closure object or FALSE on failure. This function must not violate the invariant that closures must either be both scoped and bound or static, or otherwise both unscoped and unbound. This function must prevent binding an object to the new closure if the $closure is static, however the new closure may have a different scope.
bindToDuplicates the closure designated by the current instance with a new-bound object and class scope. This method is an instance version of bind.
callCalls the closure (the current instance) with $this bound to $newthis, the class scope of the class of $newthis, and the parameters specified by $parameters. This function must fail if $newthis is NULL, or if the closure is static.

When the anonymous function creation operator is evaluated, the result is an object of type Closure (or some unspecified class derived from that type) created by the Engine. This object is referred to here as “the Closure object”. This instance encapsulates the anonymous function defined in the corresponding anonymous-function-creation-expression.

The contents of a Closure object are determined based on the context in which an anonymous function is created. Consider the following scenario:

class C
{
  public function compute()
  {
    $count = 0;
    $values = array("red" => 3, 10);
    $callback = function ($p1, $p2) use (&$count, $values)
    {
      ...
    };
    ...
  }
}

A Closure object may contain the following, optional dynamic properties, in order: static, this, and parameter.

If an anonymous-function-creation-expression contains an anonymous-function-use-clause, a dynamic property called static is present. This is unrelated to whether a closure is said to be static. This property is an array having an element for each variable-name in the use-variable-name-list, inserted in lexical order of their appearance in the use clause. Each element’s key is the corresponding variable-name, and each element value is the value of that variable at the time the time the Closure object is created (not when it is used to call the encapsulated function). In the scenario above, this leads to the following, shown as pseudo code:

$this->static = array(["count"]=>&0,["values"]=>array(["red"]=>3,[0]=>10));

If an anonymous-function-creation-expression is used inside an instance method, a dynamic property called this is present. This property is a handle that points to the current instance. In the scenario above, this leads to the following, shown as pseudo code:

$this->this = $this;

If an anonymous-function-creation-expression contains a parameter-declaration-list, a dynamic property called parameter is present. This property is an array of one or more elements, each of which corresponds to a parameter. The elements are inserted in that array in lexical order of their declaration. Each element’s key is the corresponding parameter name, and each element value is some unspecified value. (These values are overridden by the argument values used when the anonymous function is called). In the scenario above, this leads to the following, shown as pseudo code:

$property = array("$p1" => ???, "$p2" => ???)

It is possible for all three dynamic properties to be absent, in which case, the Closure object is empty.

Closure objects can not be serialized or unserialized.

Class Generator

This class supports the yield operator. This class cannot be instantiated directly. It is defined, as follows:

class Generator implements Iterator
{
  public function current();
  public function getReturn();
  public function key();
  public function next();
  public function rewind();
  public function send($value) ;
  public function throw(Exception $exception) ;
  public function valid();
}

The class members are defined below:

NamePurpose
currentAn implementation of the instance method Iterator::current.
getReturnReturns the final expression from a generator, which was produced by a return statement rather than a yield. This function can only be called meaningfully once the generator has finishing yielding values; otherwise, an instance of Exception is thrown.
keyAn implementation of the instance method Iterator::key.
nextAn implementation of the instance method Iterator::next.
rewindAn implementation of the instance method Iterator::rewind.
sendThis instance method sends the value designated by $value to the generator as the result of the current yield expression, and resumes execution of the generator. $value is the return value of the yield expression the generator is currently at. If the generator is not at a yield expression when this method is called, it will first be let to advance to the first yield expression before sending the value. This method returns the yielded value.
throwThis instance method throws an exception into the generator and resumes execution of the generator. The behavior is as if the current yield expression was replaced with throw $exception. If the generator is already closed when this method is invoked, the exception will be thrown in the caller’s context instead. This method returns the yielded value.
validAn implementation of the instance method Iterator::valid.

Generator objects can not be serialized or unserialized.

Class __PHP_Incomplete_Class

There are certain circumstances in which a program can generate an instance of this class, which on its own contains no members. One involves an attempt to unserialize a string that encodes an instance of a class for which there is no definition or if an object’s type is declared untrusted by unserialize’s filter argument.

Consider the following code:

class Point
{
  private $x;
  private $y;
  ...
}
$p = new Point(2, 5);
$s = serialize($p); // properties $x and $y are serialized, in that order

Let us assume that the serialized string is stored in a database from where it is retrieved by a separate program. That program contains the following code, but does not contain a definition of the class Point:

$v = unserialize($s);

Instead of returning a point, Point(2, 5), an instance of __PHP_Incomplete_Class results, with the following contents:

__PHP_Incomplete_Class
{
   __PHP_Incomplete_Class_Name => "Point"
  x:Point:private => 2
  y:Point:private => 5
}

Object of this class can be serialized, however, any attempt to call its method or access its property for any other operation except serialization will result in a fatal error.

Class stdClass

This class contains no members. It can be instantiated and used as a base class. An instance of this type is automatically created when a non-object is converted to an object, or the member selection operator is applied to NULL, FALSE, or an empty string.

Predefined Error Classes

PHP has a number of predefined classes that are used for error reporting. All these classes extend the base Error class.

Class Error

This class is the base class for all internal PHP error exceptions. It is defined, as follows:

class Error implements Throwable
{
  protected $message = '';
  protected $code = 0;
  protected $file;
  protected $line;

  public function __construct($message = "", $code = 0,
               Throwable $previous = NULL);

  final private function __clone();
}

For information about the base interface, see Throwable. Note that the methods from Throwable are implemented as final in the Error class, which means the extending class can not override them.

Class ArithmeticError

An instance of this class is thrown when an error occurs during certain mathematical operations. It is defined, as follows:

class ArithmeticError extends Error
{
}

Class AssertionError

An instance of this class is thrown when an assertion made via the intrinsic assert fails. The class type is defined, as follows:

class AssertionError extends Error
{
}

Class DivisionByZeroError

An instance of this class is thrown when an attempt is made to divide a number by zero, e.g. when using the remainder operators (% and %=). Note that this happens only for integer operations, regular float division (/) produces a non-fatal error instead. The class type is defined, as follows:

class DivisionByZeroError extends Error
{
}

Class ParseError

An instance of this class is thrown when an error occurs while parsing PHP code (such as when calling the intrinsic eval). It is defined, as follows:

class ParseError extends Error
{
}

Class TypeError

An instance of this class is thrown when any of the following occurs:

  • The type of an argument being passed to a function does not match its corresponding parameter’s declared type.
  • The type of the value being returned from a function does not match the function’s declared return type.
  • In strict mode, an invalid number of arguments are passed to a library function.

The class is defined, as follows:

class TypeError extends Error
{
}

See also class Exception.

Interfaces

General

A class can implement a set of capabilities — herein called a contract — through what is called an interface. An interface is a set of method declarations and constants. Note that the methods are only declared, not defined; that is, an interface defines a type consisting of abstract methods, where those methods are implemented by client classes as they see fit. An interface allows unrelated classes to implement the same facilities with the same names and types without requiring those classes to share a common base class.

An interface can extend one or more other interfaces, in which case, it inherits all members from its base interface(s).

Interface Declarations

Syntax

interface-declaration:
   interface   name   interface-base-clauseopt   {   interface-member-declarationsopt   }

interface-base-clause:
   extends   qualified-name
   interface-base-clause   ,   qualified-name

Constraints

An interface must not be derived directly or indirectly from itself.

Every qualified-name must name an interface type.

Semantics

An interface-declaration defines a contract that one or more classes can implement.

Interface names are case-insensitive.

The optional interface-base-clause specifies the base interfaces from which the interface being defined is derived. In such a case, the derived interface inherits all the members from the base interfaces.

Examples

interface MyCollection
{
  const MAX_NUMBER_ITEMS = 1000;
  function put($item);
  function get();
}
class MyList implements MyCollection
{
  public function put($item)  { /* implement method */ }
  public function get()   { /* implement method */ }
  ...
}
class MyQueue implements MyCollection
{
  public function put($item)  { /* implement method */ }
  public function get()   { /* implement method */ }
  ...
}
function processCollection(MyCollection $p1)
{
  ... /* can process any object whose class implements MyCollection */
}
processCollection(new MyList(...));
processCollection(new MyQueue(...));

Interface Members

Syntax

interface-member-declarations:
   interface-member-declaration
   interface-member-declarations   interface-member-declaration

interface-member-declaration:
   class-const-declaration
   method-declaration

Semantics

The members of an interface are those specified by its interface-member-declaration, and the members inherited from its base interfaces.

An interface may contain the following members:

  • Constants – the constant values associated with the interface.
  • Methods – placeholders for the computations and actions that can be performed by implementers of the interface.

Constants

Constraints

All constants declared in an interface must be implicitly or explicitly public.

Semantics

An interface constant is just like a class constant, except that an interface constant cannot be overridden by a class that implements it nor by an interface that extends it.

Examples

interface MyCollection
{
  const MAX_NUMBER_ITEMS = 1000;
  function put($item);
  function get();
}

Methods

Constraints

All methods declared in an interface must be implicitly or explicitly public, and they must not be declared abstract.

Semantics

An interface method is just like an abstract method.

Examples

interface MyCollection
{
  const MAX_NUMBER_ITEMS = 1000;
  function put($item);
  function get();
}

Predefined Interfaces

Interface ArrayAccess

This interface allows an instance of an implementing class to be accessed using array-like notation. This interface is defined, as follows:

interface ArrayAccess
{
  function offsetExists($offset);
  function offsetGet($offset);
  function offsetSet($offset, $value);
  function offsetUnset($offset);
}

The interface members are defined below:

NamePurpose
offsetExistsThis instance method returns TRUE if the instance contains an element with key $offset, otherwise, FALSE.
offsetGetThis instance method gets the value having key $offset. It may return by value or byRef. (Ordinarily, this wouldn’t be allowed because a class implementing an interface needs to match the interface’s method signatures; however, the Engine gives special treatment to ArrayAccess and allows this). This method is called when an instance of a class that implements this interface is subscripted in a non-lvalue context.
offsetSetThis instance method sets the value having key $offset to $value. It returns no value. This method is called when an instance of a class that implements this interface is subscripted in a modifiable-lvalue context.
offsetUnsetThis instance method unsets the value having key $offset. It returns no value.

Interface Iterator

This interface allows instances of an implementing class to be treated as a collection. This interface is defined, as follows:

interface Iterator extends Traversable
{
  function current();
  function key();
  function next();
  function rewind();
  function valid();
}

The interface members are defined below:

NamePurpose
currentThis instance method returns the element at the current position.
keyThis instance method returns the key of the current element. On failure, it returns NULL; otherwise, it returns the scalar value of the key.
nextThis instance method moves the current position forward to the next element. It returns no value. From within a foreach statement, this method is called after each loop.
rewindThis instance method resets the current position to the first element. It returns no value. From within a foreach statement, this method is called once, at the beginning.
validThis instance method checks if the current position is valid. It takes no arguments. It returns a bool value of TRUE to indicate the current position is valid; FALSE, otherwise. This method is called after each call to Iterator::rewind() and Iterator::next().

Interface IteratorAggregate

This interface allows the creation of an external iterator. This interface is defined, as follows:

interface IteratorAggregate extends Traversable
{
  function getIterator();
}

The interface members are defined below:

NamePurpose
getIteratorThis instance method retrieves an iterator, which implements Iterator or Traversable. It throws an Exception on failure.

Interface Throwable

This type is the base interface for the type of any object that can be thrown via a throw statement. A user-written class cannot implement Throwable directly. Instead, it must extend Error or Exception.

This type is defined, as follows:

interface Throwable {
  function __toString(): string;
  function getCode(): int;
  function getFile(): string;
  function getLine(): int;
  function getMessage(): string;
  function getPrevious(): Throwable;
  function getTrace(): array;
  function getTraceAsString(): string;
}

The interface members are defined below:

NamePurpose
__toStringstring; retrieves a string representation of the exception in some unspecified format
getCodeint; retrieves the exception code
getFilestring; retrieves the name of the script where the exception was generated
getLineint; retrieves the source line number in the script where the exception was generated
getMessagestring; retrieves the exception message
getPreviousThrowable; retrieves the previous exception, if one exists; otherwise returns NULL
getTracearray; retrieves the function stack trace information as an array
getTraceAsStringstring; retrieves the function stack trace information formatted as a single string in some unspecified format

Interface Traversable

This interface is intended as the base interface for all traversable classes. This interface is defined, as follows:

interface Traversable
{
}

This interface has no members.

Interface Serializable

This interface provides support for custom serialization. It is defined, as follows:

interface Serializable
{
  function serialize();
  function unserialize ($serialized);

}

The interface members are defined below:

NamePurpose
serializeThis instance method returns a string representation of the current instance. On failure, it returns NULL.
unserializeThis instance method constructs an object from its string form designated by $serialized. It does not return a value.

Traits

General

PHP’s class model allows single inheritance only with contracts being enforced separately via interfaces. A trait can provide both implementation and contracts. Specifically, a class can inherit from a base class while also using code from one or more traits. At the same time, that class can implement contracts from one or more interfaces as well as from one or more traits. The use of a trait by a class does not involve any inheritance hierarchy, so unrelated classes can use the same trait. In summary, a trait is a set of methods and/or state information that can be reused.

Traits are designed to support classes; a trait cannot be instantiated directly.

The members of a trait each have visibility, which applies once they are used by a given class. The class that uses a trait can change the visibility of any of that trait’s members, by either widening or narrowing that visibility. For example, a private trait member can be made public in the using class, and a public trait member can be made private in that class.

Once implementation comes from both a base class and one or more traits, name conflicts can occur. However, trait usage provides the means for disambiguating such conflicts. Names gotten from a trait can also be given aliases.

A class member with a given name overrides one with the same name in any traits that class uses, which, in turn, overrides any such name from base classes.

Traits can contain both instance and static members, including both methods and properties. In the case of a trait with a static property, each class using that trait has its own instance of that property.

Methods in a trait have full access to all members of any class in which that trait is used.

Trait Declarations

Syntax

trait-declaration:
   trait   name   {   trait-member-declarationsopt   }

trait-member-declarations:
   trait-member-declaration
   trait-member-declarations   trait-member-declaration

trait-member-declaration:
   property-declaration
   method-declaration
   constructor-declaration
   destructor-declaration
   trait-use-clauses

Semantics

A trait-declaration defines a named set of members, which are made available to any class that uses that trait.

Trait names are case-insensitive.

The members of a trait are those specified by its trait-member-declaration clauses, and members imported from any other traits using trait-use-clauses.

A trait may contain the following members:

  • Properties – the variables made available to the class in which the trait is used.
  • Methods – the computations and actions that can be performed by the class in which the trait is used.
  • Constructor – the actions required to initialize an instance of the class in which the trait is used.
  • Destructor – the actions to be performed when an instance of the class in which the trait is used is no longer needed.

If a member has no explicit visibility, public is assumed.

Examples

trait T
{
  private $prop1 = 1000;
  protected static $prop2;
  var $prop3;
  public function compute( ... ) { ... }
  public static function getData( ... ) { ... }
}

Trait Uses

Syntax

trait-use-clauses:
   trait-use-clause
   trait-use-clauses   trait-use-clause

trait-use-clause:
   use   trait-name-list   trait-use-specification

trait-name-list:
   qualified-name
   trait-name-list   ,   qualified-name

trait-use-specification:
   ;
   {   trait-select-and-alias-clausesopt   }

trait-select-and-alias-clauses:
   trait-select-and-alias-clause
   trait-select-and-alias-clauses   trait-select-and-alias-clause

trait-select-and-alias-clause:
   trait-select-insteadof-clause   ;
   trait-alias-as-clause   ;

trait-select-insteadof-clause:
   qualified-name   ::   name   insteadof   trait-name-list

trait-alias-as-clause:
   name   as   visibility-modifieropt   name
   name   as   visibility-modifier   nameopt

Constraints

The name items in trait-name-list must designate trait names, excluding the name of the trait being declared.

The left-hand name in trait-select-insteadof-clause must unambiguously designate a member of a trait made available by trait-use-clauses. The right-hand name in trait-select-insteadof-clause must unambiguously designate a trait made available by trait-use-clauses.

The left-hand name in trait-alias-as-clause must unambiguously designate a member of a trait made available by trait-use-clauses. The right-hand name in trait-alias-as-clause must be a new, unqualified name.

Semantics

trait-use-clauses can be used as part of trait-member-declarations or class-member-declarations to import members of a trait into a different trait or a class. This is done via one or more trait-use-clause items, each of which contains a comma-separated list of trait names. A trait-use-clause list ends in a semicolon or a brace-delimited set of trait-select-insteadof-clause and trait-alias-as-clause statements.

A trait-select-insteadof-clause allows to avoid name clashes. Specifically, the left-hand name designates which name to be used from of a pair of names. That is, T1::compute insteadof T2; indicates that calls to method compute, for example, should be satisfied by a method of that name in trait T1 rather than T2.

A trait-alias-as-clause allows a (possibly qualified) name to be assigned a simple alias name. Specifically, the left-hand name in trait-alias-as-clause designates a name made available by trait-use-clauses - that is to be aliased, and the right-hand name is the alias.

If trait-alias-as-clause contains a visibility-modifier, if a right-hand name is provided, the modifier controls the visibility of the alias, otherwise, it controls the visibility of the left-hand name.

Examples

trait T1 { public function compute( ... ) { ... } }
trait T2 { public function compute( ... ) { ... } }
trait T3 { public function sort( ... ) { ... } }
trait T4
{
  use T3;
  use T1, T2
  {
    T1::compute insteadof T2; // disambiguate between two computes
    T3::sort as private sorter; // make alias with adjusted visibility
  }
}

Exception Handling

General

An exception is some unusual condition in that it is outside the ordinary expected behavior. Examples include dealing with situations in which a critical resource is needed, but is unavailable, and detecting an out-of-range value for some computation. As such, exceptions require special handling. This chapter describes how exceptions can be created and handled.

Whenever some exceptional condition is detected at runtime, an exception is thrown. A designated exception handler can catch the thrown exception and service it. Among other things, the handler might recover from the situation completely (allowing the script to continue execution), it might perform some recovery and then throw an exception to get further help, or it might perform some cleanup action and terminate the script. Exceptions may be thrown on behalf of the Engine or by explicit code source code in the script.

Exception handling involves the use of the following keywords:

  • try, which allows a try-block of code containing one or more possible exception generations, to be tried.
  • catch, which defines a handler for a specific type of exception thrown from the corresponding try-block or from some function it calls.
  • finally, which allows the finally-block of a try-block to be executed (to perform some cleanup, for example), whether or not an exception occurred within that try-block.
  • throw, which generates an exception of a given type, from a place called a throw point.

When an exception is thrown, an exception object of type Exception, or of a subclass of that type, is created and made available to the first catch-handler that can catch it. Among other things, the exception object contains an exception message and an exception code, both of which can be used by a handler to determine how to handle the situation.

PHP errors also can be translated to exceptions via the class ErrorException (which is not part of this specification).

Class Exception

Class Exception is the base class of all exception types. This class is defined, as follows:

class Exception implements Throwable
{
  protected $message = 'Unknown exception';
  protected $code = 0;
  protected $file;
  protected $line;

  public function __construct($message = "", $code = 0,
               Throwable $previous = NULL);

  final private function __clone();
}

For information about exception trace-back and nested exceptions, see tracing exceptions.

For information about the base interface, see Throwable. Note that the methods from Throwable are implemented as final in the Exception class, which means the extending class can not override them.

The class members are defined below:

NamePurpose
$codeint; the exception code (as provided by the constructor)
$filestring; the name of the script where the exception was generated
$lineint; the source line number in the script where the exception was generated
$messagestring; the exception message (as provided by the constructor)
__constructTakes three (optional) arguments – string: the exception message (defaults to “”), int: the exception code (defaults to 0), and Exception: the previous exception in the chain (defaults to NULL)
__clonePresent to inhibit the cloning of exception objects

Tracing Exceptions

When an exception is caught, the get* functions in class Exception provide useful information. If one or more nested function calls were involved to get to the place where the exception was generated, a record of those calls is also retained, and made available by getTrace, through what is referred to as the *function stack trace*, or simply, trace`.

Let’s refer to the top level of a script as function-level 0. Function-level 1 is inside any function called from function-level 0. Function-level 2 is inside any function called from function-level 1, and so on. The method getTrace returns an array. Exceptions generated at function-level 0 involve no function call, in which case, the array returned by getTrace is empty.

Each element of the array returned by getTrace provides information about a given function level. Let us call this array trace-array and the number of elements in this array call-level. The key for each of trace-array’s elements has type int, and ranges from 0 to call-level - 1. For example, when a top-level script calls function f1, which calls function f2, which calls function f3, which then generates an exception, there are four function levels, 0–3, and there are three lots of trace information, one per call level. That is, trace-array contains three elements, and they each correspond to the reverse order of the function calls. For example, trace-array[0] is for the call to function f3, trace-array[1] is for the call to function f2, and trace-array[2] is for the call to function f1.

Each element in trace-array is itself an array that contains elements with the following key/value pairs:

KeyValue TypeValue
“args”arrayThe set of arguments passed to the function
“class”stringThe name of the function’s parent class
“file”stringThe name of the script where the function was called
“function”stringThe name of the function or class method
“line”intThe line number in the source where the function was called
“object”objectThe current object
“type”stringType of call; -> for an instance method call, :: for a static method call, for ordinary function call, empty string("") is returned.

The key args has a value that is yet another array, which we shall call argument-array. That array contains a set of values that corresponds directly to the set of values passed as arguments to the corresponding function. Regarding element order, argument-array[0] corresponds to the left-most argument, argument-array[1] corresponds to the next argument to the right, and so on.

Note that only the actual arguments passed to the function are reported. Consider the case in which a function has a default argument value defined for a parameter. If that function is called without an argument for the parameter having the default value, no corresponding argument exists in the argument array. Only arguments present at the function-call site have their values recorded in array-argument.

See also, library functions debug_backtrace and debug_print_backtrace.

User-Defined Exception Classes

An exception class is defined simply by having it extend class Exception. However, as that class’s __clone method is declared final, exception objects cannot be cloned.

When an exception class is defined, typically, its constructors call the parent class’ constructor as their first operation to ensure the base-class part of the new object is initialized appropriately. They often also provide an augmented implementation of __toString().

Namespaces

General

A problem encountered when managing large projects is that of avoiding the use of the same name in the same scope for different purposes. This is especially problematic in a language that supports modular design and component libraries.

A namespace is a container for a set of (typically related) definitions of classes, interfaces, traits, functions, and constants. Namespaces serve two purposes:

  • They help avoid name collisions.
  • They allow certain long names to be accessed via shorter, more convenient and readable, names.

A namespace may have sub-namespaces, where a sub-namespace name shares a common prefix with another namespace. For example, the namespace Graphics might have sub-namespaces Graphics\D2 and Graphics\D3, for two- and three-dimensional facilities, respectively. Apart from their common prefix, a namespace and its sub-namespaces have no special relationship. The namespace whose prefix is part of a sub-namespace need not actually exist for the sub-namespace to exist. That is, NS1\Sub can exist without NS1.

In the absence of any namespace definition, the names of subsequent classes, interfaces, traits, functions, and constants are in the default namespace, which has no name, per se.

The namespaces PHP, php, and sub-namespaces beginning with those prefixes are reserved for use by PHP.

Defining Namespaces

Syntax

namespace-definition:
   namespace   namespace-name   ;
   namespace   namespace-nameopt   compound-statement

Constraints

Except for white space and declare-statement, the first occurrence of a namespace-definition in a script must be the first thing in that script.

All occurrence of a namespace-definition in a script must have the compound-statement form or must not have that form; the two forms cannot be mixed within the same script file.

When a script contains source code that is not inside a namespace, and source code that is inside one or namespaces, the namespaced code must use the compound-statement form of namespace-definition.

compound-statement must not contain a namespace-definition.

Semantics

Although a namespace may contain any PHP source code, the fact that that code is contained in a namespace affects only the declaration and name resolution of classes, interfaces, traits, functions, and constants. For each of those, if they are defined using unqualified or qualified name, the current namespace name is prepended to the specified name. Note that while definition has a short name, the name known to the engine is always the full name, and can be either specified as fully qualified name, composed from current namespace name and specified name, or imported.

Namespace and sub-namespace names are case-insensitive.

The pre-defined constant __NAMESPACE__ contains the name of the current namespace.

When the same namespace is defined in multiple scripts, and those scripts are combined into the same program, the namespace is considered the merger of its individual contributions.

The scope of the non-compound-statement form of namespace-definition runs until the end of the script, or until the lexically next namespace-definition, whichever comes first. The scope of the compound-statement form is the compound-statement.

Examples

Script1.php:

namespace NS1;
...       // __NAMESPACE__ is "NS1"
namespace NS3\Sub1;
...       // __NAMESPACE__ is "NS3\Sub1"

Script2.php:

namespace NS1
{
...       // __NAMESPACE__ is "NS1"
}
namespace
{
...       // __NAMESPACE__ is ""
}
namespace NS3\Sub1;
{
...       // __NAMESPACE__ is "NS3\Sub1"
}

Namespace Use Declarations

Syntax

namespace-use-declaration:
   use   namespace-function-or-constopt   namespace-use-clauses   ;
   use   namespace-function-or-const   \opt   namespace-name   \   {   namespace-use-group-clauses-1   }   ;
   use   \opt   namespace-name   \   {   namespace-use-group-clauses-2   }   ;

namespace-use-clauses:
   namespace-use-clause
   namespace-use-clauses   ,   namespace-use-clause

namespace-use-clause:
   qualified-name   namespace-aliasing-clauseopt

namespace-aliasing-clause:
   as   name

namespace-function-or-const:
   function
   const

namespace-use-group-clauses-1:
   namespace-use-group-clause-1
   namespace-use-group-clauses-1   ,   namespace-use-group-clause-1

namespace-use-group-clause-1:
   namespace-name   namespace-aliasing-clauseopt

namespace-use-group-clauses-2:
   namespace-use-group-clause-2
   namespace-use-group-clauses-2   ,   namespace-use-group-clause-2

namespace-use-group-clause-2:
   namespace-function-or-constopt   namespace-name   namespace-aliasing-clauseopt

Constraints

A namespace-use-declaration must not occur except at the top level or directly in the context of a namespace-definition.

If the same qualified-name, name, or namespace-name is imported multiple times in the same scope, each occurrence must have a different alias.

Semantics

If namespace-use-declaration has a namespace-function-or-const with value function, the statement imports one or more functions. If namespace-use-declaration has a namespace-function-or-const with value const, the statement imports one or more constants. Otherwise, namespace-use-declaration has no namespace-function-or-const. In that case, if namespace-use-clauses is present, the names being imported are considered to be classes/interfaces/traits. Otherwise, namespace-use-group-clauses-2 is present, in which case, the names being imported are considered to be functions, constants, or classes/interfaces/traits based on the respective presence of function or const, or the absence of namespace-function-or-const on each namespace-name in subordinate namespace-use-group-clause-2s.

Note that constant, function and class imports live in different spaces, so the same name can be used as function and class import and apply to the respective cases of class and function use, without interfering with each other.

A namespace-use-declaration imports — that is, makes available — one or more names into a scope, optionally giving them each an alias. Each of those names may designate a namespace, a sub-namespace, a class, an interface, or a trait. If a namespace-aliasing-clause is present, its name is the alias for qualified-name, name, or namespace-name. Otherwise, the right-most name component in qualified-name is the implied alias for qualified-name.

Examples

namespace NS1
{
  const CON1 = 100;
  function f() { ... }
  class C { ... }
  interface I { ... }
  trait T { ... }
}

namespace NS2
{
  use \NS1\C, \NS1\I, \NS1\T;
  class D extends C implements I
  {
    use T;  // trait (and not a namespace use declaration)
  }
  $v = \NS1\CON1; // explicit namespace still needed for constants
  \NS1\f();   // explicit namespace still needed for functions

  use \NS1\C as C2; // C2 is an alias for the class name \NS1\C
  $c2 = new C2;

  // importing a group of classes and interfaces
  use \NS\{C11, C12, I10};

  // importing a function
  use function \My\Full\functionName;

  // aliasing a function
  use function \NS1\f as func;
  use function \NS\{f1, g1 as myG};

  // importing a constant
  use const \NS1\CON1;
  use \NS\{const CON11, const CON12};

  $v = CON1; // imported constant
  func();   // imported function

  // importing a class, a constant, and a function
  use \NS\ { C2 as CX, const CON2 as CZ, function f1 as FZ };
}

Note that the qualified-name is treated as absolute even if it does not start with \. For example:

namespace b
{
  class B
  {
    function foo(){ echo "goodbye"; }
  }
}

namespace a\b
{
  class B
  {
    function foo(){ echo "hello"; }
  }
}

namespace a
{
  $b = new b\B();
  $b->foo(); // hello
  use b\B as C;
  $b = new C();
  $b->foo(); // goodbye
}

Name Lookup

When an existing name is used in source code, the Engine must determine how that name is found with respect to namespace lookup. For this purpose, names can have one of the three following forms:

  • Unqualified name: Such names are just simple names without any prefix, as in the class name Point in the following expression: $p = new Point(3,5). If the current namespace is NS1, the name Point resolves to NS1\Point. If the current namespace is the default namespace, the name Point resolves to just Point. In the case of an unqualified function or constant name, if that name does not exist in the current namespace, a global function or constant by that name is used.
  • Qualified name: Such names have a prefix consisting of a namespace name and/or one or more levels of sub-namespace names, preceding a class, interface, trait, function, or constant name. Such names are relative. For example, D2\Point could be used to refer to the class Point in the sub-namespace D2 of the current namespace. One special case of this is when the first component of the name is the keyword namespace. This means “the current namespace”.
  • Fully qualified name: Such names begin with a backslash (\) and are followed optionally by a namespace name and one or more levels of sub-namespace names, and, finally, a class, interface, trait, function, or constant name. Such names are absolute. For example, \Graphics\D2\Point could be used to refer unambiguously to the class Point in namespace Graphics, sub-namespace D2.

However, if an unqualified name is used in a context where it represents the name of a constant or function, within a non-default namespace, if this namespace does not have such constant of function defined, the global unqualified name is used.

For example:

<?php
namespace A\B\C;
function strlen($str)
{
    return 42;
}
print strlen("Life, Universe and Everything"); // prints 42
print mb_strlen("Life, Universe and Everything"); // calls global function and prints 29

The names of the standard types (such as Exception), constants (such as PHP_INT_MAX), and library functions (such as is_null) are defined outside any namespace. To refer unambiguously to such names, one can prefix them with a backslash (\), as in \Exception, \PHP_INT_MAX, and \is_null.

Grammar

General

The grammar notation is described in Grammars section.

Lexical Grammar

input-file::
   input-element
   input-file   input-element

input-element::
   comment
   white-space
   token

comment::
   single-line-comment
   delimited-comment

single-line-comment::
   //   input-charactersopt
   #   input-charactersopt

input-characters::
   input-character
   input-characters   input-character

input-character::
   Any source character except   new-line

new-line::
   Carriage-return character (0x0D)
   Line-feed character (0x0A)
   Carriage-return character (0x0D) followed by line-feed character (0x0A)

delimited-comment::
   /*   No characters or any source character sequence except */   */

white-space::
   white-space-character
   white-space   white-space-character

white-space-character::
   new-line
   Space character (0x20)
   Horizontal-tab character (0x09)

token::
   variable-name
   name
   keyword
   integer-literal
   floating-literal
   string-literal
   operator-or-punctuator

variable-name::
   $   name

namespace-name::
   name
   namespace-name   \   name

namespace-name-as-a-prefix::
   \
   \opt   namespace-name   \
   namespace   \
   namespace   \   namespace-name   \

qualified-name::
   namespace-name-as-a-prefixopt   name

name::
   name-nondigit
   name   name-nondigit
   name   digit

name-nondigit::
   nondigit
   one of the characters 0x80–0xff

nondigit:: one of
   _
   a   b   c   d   e   f   g   h   i   j   k   l   m
   n   o   p   q   r   s   t   u   v   w   x   y   z
   A   B   C   D   E   F   G   H   I   J   K   L   M
   N   O   P   Q   R   S   T   U   V   W   X   Y   Z

keyword:: one of
   abstract   and   array   as   break   callable   case   catch   class   clone
   const   continue   declare   default   die   do   echo   else   elseif   empty
   enddeclare   endfor   endforeach   endif   endswitch   endwhile   eval   exit
   extends   final   finally   for   foreach   function   global
   goto   if   implements   include   include_once   instanceof
   insteadof   interface   isset   list   namespace   new   or   print   private
   protected   public   require   require_once   return   static   switch
   throw   trait   try   unset   use   var   while   xor   yield   yield from

integer-literal::
   decimal-literal
   octal-literal
   hexadecimal-literal
   binary-literal

decimal-literal::
   nonzero-digit
   decimal-literal   digit

octal-literal::
   0
   octal-literal   octal-digit

hexadecimal-literal::
   hexadecimal-prefix   hexadecimal-digit
   hexadecimal-literal   hexadecimal-digit

hexadecimal-prefix:: one of
   0x   0X

binary-literal::
   binary-prefix   binary-digit
   binary-literal   binary-digit

binary-prefix:: one of
   0b   0B

digit:: one of
   0   1   2   3   4   5   6   7   8   9

nonzero-digit:: one of
   1   2   3   4   5   6   7   8   9

octal-digit:: one of
   0   1   2   3   4   5   6   7

hexadecimal-digit:: one of
   0   1   2   3   4   5   6   7   8   9
   a   b   c   d   e   f
   A   B   C   D   E   F

binary-digit:: one of
   0   1

floating-literal::
   fractional-literal   exponent-partopt
   digit-sequence   exponent-part

fractional-literal::
   digit-sequenceopt   .   digit-sequence
   digit-sequence   .

exponent-part::
   e   signopt   digit-sequence
   E   signopt   digit-sequence

sign:: one of
   +   -

digit-sequence::
   digit
   digit-sequence   digit

string-literal::
   single-quoted-string-literal
   double-quoted-string-literal
   heredoc-string-literal
   nowdoc-string-literal

single-quoted-string-literal::
   b-prefixopt   '   sq-char-sequenceopt   '

sq-char-sequence::
   sq-char
   sq-char-sequence   sq-char

sq-char::
   sq-escape-sequence
   \opt   any member of the source character set except single-quote (') or backslash (\)

sq-escape-sequence:: one of
   \'   \\

b-prefix:: one of
   b   B

double-quoted-string-literal::
   b-prefixopt   "   dq-char-sequenceopt   "

dq-char-sequence::
   dq-char
   dq-char-sequence   dq-char

dq-char::
   dq-escape-sequence
   any member of the source character set except double-quote (") or backslash (\)
   \   any member of the source character set except "\$efnrtvxX or   octal-digit

dq-escape-sequence::
   dq-simple-escape-sequence
   dq-octal-escape-sequence
   dq-hexadecimal-escape-sequence
   dq-unicode-escape-sequence

dq-simple-escape-sequence:: one of
   \"   \\   \$   \e   \f   \n   \r   \t   \v

dq-octal-escape-sequence::
   \   octal-digit
   \   octal-digit   octal-digit
   \   octal-digit   octal-digit   octal-digit

dq-hexadecimal-escape-sequence::
   \x   hexadecimal-digit   hexadecimal-digitopt
   \X   hexadecimal-digit   hexadecimal-digitopt

dq-unicode-escape-sequence::
   \u{   codepoint-digits   }

codepoint-digits::
   hexadecimal-digit
   hexadecimal-digit   codepoint-digits

string-variable::
   variable-name   offset-or-propertyopt
   ${   expression   }

offset-or-property::
   offset-in-string
   property-in-string

offset-in-string::
   [   name   ]
   [   variable-name   ]
   [   integer-literal   ]

property-in-string::
   ->   name

heredoc-string-literal::
   b-prefixopt   <<<   hd-start-identifier   new-line   hd-bodyopt   hd-end-identifier   ;opt   new-line

hd-start-identifier::
   name
   "   name   "

hd-end-identifier::
   name

hd-body::
   hd-char-sequenceopt   new-line

hd-char-sequence::
   hd-char
   hd-char-sequence   hd-char

hd-char::
   hd-escape-sequence
   any member of the source character set except backslash (\)
   \ any member of the source character set except \$efnrtvxX or   octal-digit

hd-escape-sequence::
   hd-simple-escape-sequence
   dq-octal-escape-sequence
   dq-hexadecimal-escape-sequence
   dq-unicode-escape-sequence

hd-simple-escape-sequence:: one of
   \\   \$   \e   \f   \n   \r   \t   \v

nowdoc-string-literal::
   b-prefixopt   <<<   '   name   '   new-line   hd-bodyopt   name   ;opt   new-line

operator-or-punctuator:: one of
   [   ]   (   )   {   }   .   ->   ++   --   **   *   +   -   ~   !
   $   /   %   <<   >>   <   >   <=   >=   ==   ===   !=   !==   ^   |
   &   &&   ||   ?   :   ;   =   **=   *=   /=   %=   +=   -=   .=   <<=
   >>=   &=   ^=   |=   ,   ??   <=>   ...   \

Syntactic Grammar

Basic Concepts

script:
   script-section
   script   script-section

script-section:
   textopt   start-tag   statement-listopt   end-tagopt   textopt

start-tag:
   <?php
   <?=

end-tag:
   ?>

text:
   arbitrary text not containing any of   start-tag   sequences

Variables

function-static-declaration:
   static   static-variable-name-list   ;

static-variable-name-list:
   static-variable-declaration
   static-variable-name-list   ,   static-variable-declaration

static-variable-declaration:
   variable-name   function-static-initializeropt

function-static-initializer:
   =   constant-expression

global-declaration:
   global   variable-name-list   ;

variable-name-list:
   simple-variable
   variable-name-list   ,   simple-variable

Expressions

primary-expression:
   variable
   class-constant-access-expression
   constant-access-expression
   literal
   array-creation-expression
   intrinsic
   anonymous-function-creation-expression
   object-creation-expression
   postfix-increment-expression
   postfix-decrement-expression
   prefix-increment-expression
   prefix-decrement-expression
   byref-assignment-expression
   shell-command-expression
   (   expression   )

simple-variable:
   variable-name
   $   simple-variable
   $   {   expression   }

dereferencable-expression:
   variable
   (   expression   )
   array-creation-expression
   string-literal

callable-expression:
   callable-variable
   (   expression   )
   array-creation-expression
   string-literal

callable-variable:
   simple-variable
   subscript-expression
   member-call-expression
   scoped-call-expression
   function-call-expression

variable:
   callable-variable
   scoped-property-access-expression
   member-access-expression

constant-access-expression:
   qualified-name

literal:
   integer-literal
   floating-literal
   string-literal

intrinsic:
   empty-intrinsic
   eval-intrinsic
   exit-intrinsic
   isset-intrinsic

empty-intrinsic:
   empty   (   expression   )

eval-intrinsic:
   eval   (   expression   )

exit-intrinsic:
   exit
   exit   (   expressionopt   )
   die
   die   (   expressionopt   )

isset-intrinsic:
   isset   (   variable-list   ,opt   )

variable-list:
   variable
   variable-list   ,   variable

anonymous-function-creation-expression:
   staticopt   function   &opt   (   parameter-declaration-listopt   )   anonymous-function-use-clauseopt   return-typeopt   compound-statement

anonymous-function-use-clause:
   use   (   use-variable-name-list   )

use-variable-name-list:
   &opt   variable-name
   use-variable-name-list   ,   &opt   variable-name

object-creation-expression:
   new   class-type-designator   (   argument-expression-listopt   )
   new   class-type-designator   (   argument-expression-list   ,opt   )
   new   class-type-designator
   new   class   (   argument-expression-listopt   )   class-base-clauseopt   class-interface-clauseopt   {   class-member-declarationsopt   }
   new   class   class-base-clauseopt   class-interface-clauseopt   {   class-member-declarationsopt   }

class-type-designator:
   qualified-name
   new-variable

new-variable:
   simple-variable
   new-variable   [   expressionopt   ]
   new-variable   {   expression   }
   new-variable   ->   member-name
   qualified-name   ::   simple-variable
   relative-scope   ::   simple-variable
   new-variable   ::   simple-variable

array-creation-expression:
   array   (   array-initializeropt   )
   [   array-initializeropt   ]

array-initializer:
   array-initializer-list   ,opt

array-initializer-list:
   array-element-initializer
   array-element-initializer   ,   array-initializer-list

array-element-initializer:
   &opt   element-value
   element-key   =>   &opt   element-value

element-key:
   expression

element-value:
   expression

subscript-expression:
   dereferencable-expression   [   expressionopt   ]
   dereferencable-expression   {   expression   }   <b>[Deprecated form]</b>

function-call-expression:
   qualified-name   (   argument-expression-listopt   )
   qualified-name   (   argument-expression-list   ,   )
   callable-expression   (   argument-expression-listopt   )
   callable-expression   (   argument-expression-list   ,   )

argument-expression-list:
   argument-expression
   argument-expression-list   ,   argument-expression

argument-expression:
   variadic-unpacking
   expression

variadic-unpacking:
   ...   expression

member-access-expression:
   dereferencable-expression   ->   member-name

member-name:
   name
   simple-variable
   {   expression   }

member-call-expression:
   dereferencable-expression   ->   member-name   (   argument-expression-listopt   )
   dereferencable-expression   ->   member-name   (   argument-expression-list   ,   )

postfix-increment-expression:
   variable   ++

postfix-decrement-expression:
   variable   --

prefix-increment-expression:
   ++   variable

prefix-decrement-expression:
   --   variable

shell-command-expression:
   `   dq-char-sequenceopt   `

scoped-property-access-expression:
   scope-resolution-qualifier   ::   simple-variable

scoped-call-expression:
   scope-resolution-qualifier   ::   member-name   (   argument-expression-listopt   )
   scope-resolution-qualifier   ::   member-name   (   argument-expression-list   ,   )

class-constant-access-expression:
   scope-resolution-qualifier   ::   name

scope-resolution-qualifier:
   relative-scope
   qualified-name
   dereferencable-expression

relative-scope:
   self
   parent
   static

clone-expression:
   primary-expression
   clone   primary-expression

exponentiation-expression:
   clone-expression
   clone-expression   **   exponentiation-expression

unary-expression:
   exponentiation-expression
   unary-op-expression
   error-control-expression
   cast-expression

unary-op-expression:
   unary-operator   unary-expression

unary-operator: one of
   +   -   ~

error-control-expression:
   @   unary-expression

cast-expression:
   (   cast-type   )   unary-expression

cast-type: one of
   array   binary   bool   boolean   double   int   integer   float   object
   real   string   unset

instanceof-expression:
   unary-expression
   instanceof-subject   instanceof   class-type-designator

instanceof-subject:
   instanceof-expression

logical-NOT-expression:
   instanceof-expression
   !   instanceof-expression

multiplicative-expression:
   logical-NOT-expression
   multiplicative-expression   *   logical-NOT-expression
   multiplicative-expression   /   logical-NOT-expression
   multiplicative-expression   %   logical-NOT-expression

additive-expression:
   multiplicative-expression
   additive-expression   +   multiplicative-expression
   additive-expression   -   multiplicative-expression
   additive-expression   .   multiplicative-expression

shift-expression:
   additive-expression
   shift-expression   <<   additive-expression
   shift-expression   >>   additive-expression

relational-expression:
   shift-expression
   relational-expression   <   shift-expression
   relational-expression   >   shift-expression
   relational-expression   <=   shift-expression
   relational-expression   >=   shift-expression
   relational-expression   <=>   shift-expression

equality-expression:
   relational-expression
   equality-expression   ==   relational-expression
   equality-expression   !=   relational-expression
   equality-expression   <>   relational-expression
   equality-expression   ===   relational-expression
   equality-expression   !==   relational-expression

bitwise-AND-expression:
   equality-expression
   bitwise-AND-expression   &   equality-expression

bitwise-exc-OR-expression:
   bitwise-AND-expression
   bitwise-exc-OR-expression   ^   bitwise-AND-expression

bitwise-inc-OR-expression:
   bitwise-exc-OR-expression
   bitwise-inc-OR-expression   |   bitwise-exc-OR-expression

logical-AND-expression-1:
   bitwise-inc-OR-expression
   logical-AND-expression-1   &&   bitwise-inc-OR-expression

logical-inc-OR-expression-1:
   logical-AND-expression-1
   logical-inc-OR-expression-1   ||   logical-AND-expression-1

coalesce-expression:
   logical-inc-OR-expression-1
   logical-inc-OR-expression-1   ??   coalesce-expression

conditional-expression:
   coalesce-expression
   conditional-expression   ?   expressionopt   :   coalesce-expression

assignment-expression:
   conditional-expression
   simple-assignment-expression
   compound-assignment-expression

simple-assignment-expression:
   variable   =   assignment-expression
   list-intrinsic   =   assignment-expression

list-intrinsic:
   list   (   list-expression-list   )

list-expression-list:
   unkeyed-list-expression-list
   keyed-list-expression-list   ,opt

unkeyed-list-expression-list:
   list-or-variable
   ,
   unkeyed-list-expression-list   ,   list-or-variableopt

keyed-list-expression-list:
   expression   =>   list-or-variable
   keyed-list-expression-list   ,   expression   =>   list-or-variable

list-or-variable:
   list-intrinsic
   &opt   variable

byref-assignment-expression:
   variable   =   &   variable

compound-assignment-expression:
   variable   compound-assignment-operator   assignment-expression

compound-assignment-operator: one of
   **=   *=   /=   %=   +=   -=   .=   <<=   >>=   &=   ^=   |=

yield-from-expression:
   yield from   assignment-expression

yield-expression:
   yield-from-expression
   yield
   yield   yield-expression
   yield   yield-from-expression   =>   yield-expression

print-expression:
   yield-expression
   print   print-expression

logical-AND-expression-2:
   print-expression
   logical-AND-expression-2   and   yield-expression

logical-exc-OR-expression:
   logical-AND-expression-2
   logical-exc-OR-expression   xor   logical-AND-expression-2

logical-inc-OR-expression-2:
   logical-exc-OR-expression
   logical-inc-OR-expression-2   or   logical-exc-OR-expression

expression:
   logical-inc-OR-expression-2
   include-expression
   include-once-expression
   require-expression
   require-once-expression

include-expression:
   include   expression

include-once-expression:
   include_once   expression

require-expression:
   require   expression

require-once-expression:
   require_once   expression

constant-expression:
   expression

Statements

statement:
   compound-statement
   named-label-statement
   expression-statement
   selection-statement
   iteration-statement
   jump-statement
   try-statement
   declare-statement
   echo-statement
   unset-statement
   const-declaration
   function-definition
   class-declaration
   interface-declaration
   trait-declaration
   namespace-definition
   namespace-use-declaration
   global-declaration
   function-static-declaration

compound-statement:
   {   statement-listopt   }

statement-list:
   statement
   statement-list   statement

named-label-statement:
   name   :

expression-statement:
   expressionopt   ;

selection-statement:
   if-statement
   switch-statement

if-statement:
   if   (   expression   )   statement   elseif-clauses-1opt   else-clause-1opt
   if   (   expression   )   :   statement-list   elseif-clauses-2opt   else-clause-2opt   endif   ;

elseif-clauses-1:
   elseif-clause-1
   elseif-clauses-1   elseif-clause-1

elseif-clause-1:
   elseif   (   expression   )   statement

else-clause-1:
   else   statement

elseif-clauses-2:
   elseif-clause-2
   elseif-clauses-2   elseif-clause-2

elseif-clause-2:
   elseif   (   expression   )   :   statement-list

else-clause-2:
   else   :   statement-list

switch-statement:
   switch   (   expression   )   {   case-statementsopt   }
   switch   (   expression   )   :   case-statementsopt   endswitch;

case-statements:
   case-statement   case-statementsopt
   default-statement   case-statementsopt

case-statement:
   case   expression   case-default-label-terminator   statement-listopt

default-statement:
   default   case-default-label-terminator   statement-listopt

case-default-label-terminator:
   :
   ;

iteration-statement:
   while-statement
   do-statement
   for-statement
   foreach-statement

while-statement:
   while   (   expression   )   statement
   while   (   expression   )   :   statement-list   endwhile   ;

do-statement:
   do   statement   while   (   expression   )   ;

for-statement:
   for   (   for-initializeropt   ;   for-controlopt   ;   for-end-of-loopopt   )   statement
   for   (   for-initializeropt   ;   for-controlopt   ;   for-end-of-loopopt   )   :   statement-list   endfor   ;

for-initializer:
   for-expression-group

for-control:
   for-expression-group

for-end-of-loop:
   for-expression-group

for-expression-group:
   expression
   for-expression-group   ,   expression

foreach-statement:
   foreach   (   foreach-collection-name   as   foreach-keyopt   foreach-value   )   statement
   foreach   (   foreach-collection-name   as   foreach-keyopt   foreach-value   )   :   statement-list   endforeach   ;

foreach-collection-name:
   expression

foreach-key:
   expression   =>

foreach-value:
   &opt   expression
   list-intrinsic

jump-statement:
   goto-statement
   continue-statement
   break-statement
   return-statement
   throw-statement

goto-statement:
   goto   name   ;

continue-statement:
   continue   breakout-levelopt   ;

breakout-level:
   integer-literal
   (   breakout-level   )

break-statement:
   break   breakout-levelopt   ;

return-statement:
   return   expressionopt   ;

throw-statement:
   throw   expression   ;

try-statement:
   try   compound-statement   catch-clauses
   try   compound-statement   finally-clause
   try   compound-statement   catch-clauses   finally-clause

catch-clauses:
   catch-clause
   catch-clauses   catch-clause

catch-clause:
   catch   (   catch-name-list   variable-name   )   compound-statement

catch-name-list:
   qualified-name
   catch-name-list   |   qualified-name

finally-clause:
   finally   compound-statement

declare-statement:
   declare   (   declare-directive   )   statement
   declare   (   declare-directive   )   :   statement-list   enddeclare   ;
   declare   (   declare-directive   )   ;

declare-directive:
   ticks   =   literal
   encoding   =   literal
   strict_types   =   literal

echo-statement:
   echo   expression-list   ;

expression-list:
   expression
   expression-list   ,   expression

unset-statement:
   unset   (   variable-list   ,opt   )   ;

Functions

function-definition:
   function-definition-header   compound-statement

function-definition-header:
   function   &opt   name   (   parameter-declaration-listopt   )   return-typeopt

parameter-declaration-list:
   simple-parameter-declaration-list
   variadic-declaration-list

simple-parameter-declaration-list:
   parameter-declaration
   parameter-declaration-list   ,   parameter-declaration

variadic-declaration-list:
   simple-parameter-declaration-list   ,   variadic-parameter
   variadic-parameter

parameter-declaration:
   type-declarationopt   &opt   variable-name   default-argument-specifieropt

variadic-parameter:
   type-declarationopt   &opt   ...   variable-name

return-type:
   :   type-declaration
   :   void

type-declaration:
   ?opt   base-type-declaration

base-type-declaration:
   array
   callable
   iterable
   scalar-type
   qualified-name

scalar-type:
   bool
   float
   int
   string

default-argument-specifier:
   =   constant-expression

Classes

class-declaration:
   class-modifieropt   class   name   class-base-clauseopt   class-interface-clauseopt   {   class-member-declarationsopt   }

class-modifier:
   abstract
   final

class-base-clause:
   extends   qualified-name

class-interface-clause:
   implements   qualified-name
   class-interface-clause   ,   qualified-name

class-member-declarations:
   class-member-declaration
   class-member-declarations   class-member-declaration

class-member-declaration:
   class-const-declaration
   property-declaration
   method-declaration
   constructor-declaration
   destructor-declaration
   trait-use-clause

const-declaration:
   const   const-elements   ;

class-const-declaration:
   visibility-modifieropt   const   const-elements   ;

const-elements:
   const-element
   const-elements   ,   const-element

const-element:
   name   =   constant-expression

property-declaration:
   property-modifier   property-elements   ;

property-modifier:
   var
   visibility-modifier   static-modifieropt
   static-modifier   visibility-modifieropt

visibility-modifier:
   public
   protected
   private

static-modifier:
   static

property-elements:
   property-element
   property-elements   property-element

property-element:
   variable-name   property-initializeropt   ;

property-initializer:
   =   constant-expression

method-declaration:
   method-modifiersopt   function-definition
   method-modifiers   function-definition-header   ;

method-modifiers:
   method-modifier
   method-modifiers   method-modifier

method-modifier:
   visibility-modifier
   static-modifier
   class-modifier

constructor-declaration:
   method-modifiers   function   &opt   __construct   (   parameter-declaration-listopt   )   compound-statement

destructor-declaration:
   method-modifiers   function   &opt   __destruct   (   )   compound-statement

Interfaces

interface-declaration:
   interface   name   interface-base-clauseopt   {   interface-member-declarationsopt   }

interface-base-clause:
   extends   qualified-name
   interface-base-clause   ,   qualified-name

interface-member-declarations:
   interface-member-declaration
   interface-member-declarations   interface-member-declaration

interface-member-declaration:
   class-const-declaration
   method-declaration

Traits

trait-declaration:
   trait   name   {   trait-member-declarationsopt   }

trait-member-declarations:
   trait-member-declaration
   trait-member-declarations   trait-member-declaration

trait-member-declaration:
   property-declaration
   method-declaration
   constructor-declaration
   destructor-declaration
   trait-use-clauses

trait-use-clauses:
   trait-use-clause
   trait-use-clauses   trait-use-clause

trait-use-clause:
   use   trait-name-list   trait-use-specification

trait-name-list:
   qualified-name
   trait-name-list   ,   qualified-name

trait-use-specification:
   ;
   {   trait-select-and-alias-clausesopt   }

trait-select-and-alias-clauses:
   trait-select-and-alias-clause
   trait-select-and-alias-clauses   trait-select-and-alias-clause

trait-select-and-alias-clause:
   trait-select-insteadof-clause   ;
   trait-alias-as-clause   ;

trait-select-insteadof-clause:
   qualified-name   ::   name   insteadof   trait-name-list

trait-alias-as-clause:
   name   as   visibility-modifieropt   name
   name   as   visibility-modifier   nameopt

Namespaces

namespace-definition:
   namespace   namespace-name   ;
   namespace   namespace-nameopt   compound-statement

namespace-use-declaration:
   use   namespace-function-or-constopt   namespace-use-clauses   ;
   use   namespace-function-or-const   \opt   namespace-name   \   {   namespace-use-group-clauses-1   }   ;
   use   \opt   namespace-name   \   {   namespace-use-group-clauses-2   }   ;

namespace-use-clauses:
   namespace-use-clause
   namespace-use-clauses   ,   namespace-use-clause

namespace-use-clause:
   qualified-name   namespace-aliasing-clauseopt

namespace-aliasing-clause:
   as   name

namespace-function-or-const:
   function
   const

namespace-use-group-clauses-1:
   namespace-use-group-clause-1
   namespace-use-group-clauses-1   ,   namespace-use-group-clause-1

namespace-use-group-clause-1:
   namespace-name   namespace-aliasing-clauseopt

namespace-use-group-clauses-2:
   namespace-use-group-clause-2
   namespace-use-group-clauses-2   ,   namespace-use-group-clause-2

namespace-use-group-clause-2:
   namespace-function-or-constopt   namespace-name   namespace-aliasing-clauseopt

Bibliography

The following documents are useful references for implementers and users of this specification:

IEC 60559:1989, Binary floating-point arithmetic for microprocessor systems (previously designated IEC 559:1989). (This standard is widely known by its U.S. national designation, ANSI/IEEE Standard 754-1985, IEEE Standard for Binary Floating-Point Arithmetic).

The Unicode Consortium. The Unicode Standard, Version 5.0, www.Unicode.org).