Language

Attributes

Attributes overview

PHP attributes provide structured, machine-readable metadata for classes, methods, functions, parameters, properties, and constants. They can be inspected at runtime via the Reflection API, enabling dynamic behavior without modifying code. Attributes provide a declarative way to annotate code with metadata.

Attributes enable the decoupling of a feature's implementation from its usage. While interfaces define structure by enforcing methods, attributes provide metadata across multiple elements, including methods, functions, properties, and constants. Unlike interfaces, which enforce method implementations, attributes annotate code without altering its structure.

Attributes can complement or replace optional interface methods by providing metadata instead of enforced structure. Consider an ActionHandler interface that represents an operation in an application. Some implementations may require a setup step while others do not. Instead of forcing all classes implementing ActionHandler to define a setUp() method, an attribute can indicate setup requirements. This approach increases flexibility, allowing attributes to be applied multiple times when necessary.

Implementing optional methods of an interface with Attributes

<?php
interface ActionHandler
{
    public function execute();
}

#[Attribute]
class SetUp {}

class CopyFile implements ActionHandler
{
    public string $fileName;
    public string $targetDirectory;

    #[SetUp]
    public function fileExists()
    {
        if (!file_exists($this->fileName)) {
            throw new RuntimeException("File does not exist");
        }
    }

    #[SetUp]
    public function targetDirectoryExists()
    {
        if (!file_exists($this->targetDirectory)) {
            mkdir($this->targetDirectory);
        } elseif (!is_dir($this->targetDirectory)) {
            throw new RuntimeException("Target directory $this->targetDirectory is not a directory");
        }
    }

    public function execute()
    {
        copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
    }
}

function executeAction(ActionHandler $actionHandler)
{
    $reflection = new ReflectionObject($actionHandler);

    foreach ($reflection->getMethods() as $method) {
        $attributes = $method->getAttributes(SetUp::class);

        if (count($attributes) > 0) {
            $methodName = $method->getName();

            $actionHandler->$methodName();
        }
    }

    $actionHandler->execute();
}

$copyAction = new CopyFile();
$copyAction->fileName = "/tmp/foo.jpg";
$copyAction->targetDirectory = "/home/user";

executeAction($copyAction);

     

Attribute syntax

Attribute syntax consists of several key components. An attribute declaration starts with #[ and ends with ]. Inside, one or more attributes can be listed, separated by commas. The attribute name can be unqualified, qualified, or fully-qualified, as described in Using Namespaces Basics. Arguments to the attribute are optional and enclosed in parentheses (). Arguments can only be literal values or constant expressions. Both positional and named argument syntax are supported.

Attribute names and their arguments are resolved to a class, and the arguments are passed to its constructor when an instance of the attribute is requested through the Reflection API. Therefore, it is recommended to introduce a class for each attribute.

Attribute Syntax

<?php
// a.php
namespace MyExample;

use Attribute;

#[Attribute]
class MyAttribute
{
    const VALUE = 'value';

    private $value;

    public function __construct($value = null)
    {
        $this->value = $value;
    }
}

// b.php

namespace Another;

use MyExample\MyAttribute;

#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(value: 1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}

#[MyAttribute(1234), MyAttribute(5678)]
class AnotherThing
{
}

    

Reading Attributes with the Reflection API

To access attributes from classes, methods, functions, parameters, properties, and class constants, use the getAttributes method provided by the Reflection API. This method returns an array of ReflectionAttribute instances. These instances can be queried for the attribute name, arguments, and can be used to instantiate an instance of the represented attribute.

Separating the reflected attribute representation from its actual instance provides more control over error handling, such as missing attribute classes, mistyped arguments, or missing values. Objects of the attribute class are instantiated only after calling ReflectionAttribute::newInstance, ensuring that argument validation occurs at that point.

Reading Attributes using Reflection API

<?php

#[Attribute]
class MyAttribute
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }
}

#[MyAttribute(value: 1234)]
class Thing
{
}

function dumpAttributeData($reflection) {
    $attributes = $reflection->getAttributes();

    foreach ($attributes as $attribute) {
       var_dump($attribute->getName());
       var_dump($attribute->getArguments());
       var_dump($attribute->newInstance());
    }
}

dumpAttributeData(new ReflectionClass(Thing::class));

    

ENTITY

string(11) "MyAttribute"
array(1) {
  ["value"]=>
  int(1234)
}
object(MyAttribute)#3 (1) {
  ["value"]=>
  int(1234)
}

Instead of iterating over all attributes on the reflection instance, you can retrieve only those of a specific attribute class by passing the attribute class name as an argument.

Reading Specific Attributes using Reflection API

<?php
#[Attribute]
class MyAttribute
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }
}

#[MyAttribute(value: 1234)]
class Thing
{
}

function dumpMyAttributeData($reflection) {
    $attributes = $reflection->getAttributes(MyAttribute::class);

    foreach ($attributes as $attribute) {
       var_dump($attribute->getName());
       var_dump($attribute->getArguments());
       var_dump($attribute->newInstance());
    }
}

dumpMyAttributeData(new ReflectionClass(Thing::class));

     

Declaring Attribute Classes

Simple Attribute Class

<?php

namespace Example;

use Attribute;

#[Attribute]
class MyAttribute
{
}

   

To restrict the types of declarations an attribute can be applied to, pass a bitmask as the first argument to the #[Attribute] declaration.

Using target specification to restrict where attributes can be used

<?php

namespace Example;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class MyAttribute
{
}

    

Declaring MyAttribute on another type will now throw an exception during the call to ReflectionAttribute::newInstance

The following targets can be specified:

Attribute::TARGET_CLASS

Attribute::TARGET_FUNCTION

Attribute::TARGET_METHOD

Attribute::TARGET_PROPERTY

Attribute::TARGET_CLASS_CONSTANT

Attribute::TARGET_PARAMETER

Attribute::TARGET_ALL

By default, an attribute can only be used once per declaration. To allow an attribute to be repeatable, specify it in the bitmask of the #[Attribute] declaration using the Attribute::IS_REPEATABLE flag.

Using IS_REPEATABLE to allow attribute on a declaration multiple times

<?php

namespace Example;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)]
class MyAttribute
{
}

    

Basic syntax

PHP tags

When PHP processes a file, it recognizes the opening and closing tags, ENTITY?php and ?ENTITY, to define the boundaries of PHP code execution. Content outside these tags is ignored by the PHP parser, allowing PHP to seamlessly embed in various document types.

A whitespace character (space, tab, or newline) must follow ENTITY?php to ensure proper token separation. Omitting this whitespace will result in a syntax error.

PHP also includes the short echo tag ENTITY?=, which is shorthand for ENTITY?php echo.

PHP Opening and Closing Tags

1.  <?php echo 'if you want to serve PHP code in XHTML or XML documents,
                use these tags'; ?>

2.  You can use the short echo tag to <?= 'print this string' ?>.
    It's equivalent to <?php echo 'print this string' ?>.

3.  <? echo 'this code is within short tags, but will only work '.
            'if short_open_tag is enabled'; ?>

     

Short tags (the third line in the example above) are available by default but can be disabled either via the short_open_tag ENTITY configuration file directive, or are disabled by default if PHP is built with the --disable-short-tags configuration.

[!NOTE] As short tags can be disabled it is recommended to only use the normal tags (ENTITY?php ?ENTITY and ENTITY?= ?ENTITY) to maximise compatibility.

If a file ends with PHP code, it is preferable to omit the PHP closing tag at the end of the file. This prevents accidental whitespace or new lines being added after the PHP closing tag, which may cause unwanted effects because PHP will start output buffering when there is no intention from the programmer to send any output at that point in the script.

PHP Code Only File

<?php
echo "Hello world\n";

// ... more code

echo "Last statement\n";

// the script ends here with no PHP closing tag

     

Escaping from HTML

Everything outside of a pair of opening and closing tags is ignored by the PHP parser which allows PHP files to have mixed content. This allows PHP to be embedded in HTML documents, for example to create templates.

Embedding PHP in HTML

<p>This is going to be ignored by PHP and displayed by the browser.</p>
<?php echo 'While this is going to be parsed.'; ?>
<p>This will also be ignored by PHP and displayed by the browser.</p>

     

This works as expected, because when the PHP interpreter hits the ?ENTITY closing tags, it simply starts outputting whatever it finds (except for the immediately following newline - see instruction separation) until it hits another opening tag unless in the middle of a conditional statement in which case the interpreter will determine the outcome of the conditional before making a decision of what to skip over. See the next example.

Using structures with conditions

Advanced escaping using conditions

<?php if (true): ?>
  This will show if the expression is true.
<?php else: ?>
  Otherwise this will show.
<?php endif; ?>

     

In this example PHP will skip the blocks where the condition is not met, even though they are outside of the PHP open/close tags; PHP skips them according to the condition since the PHP interpreter will jump over blocks contained within a condition that is not met.

For outputting large blocks of text, dropping out of PHP parsing mode is generally more efficient than sending all of the text through echo or print.

[!NOTE] If PHP is embedded within XML or XHTML the normal PHP ENTITY?php ?ENTITY must be used to remain compliant with the standards.

Instruction separation

As in C or Perl, PHP requires instructions to be terminated with a semicolon at the end of each statement. The closing tag of a block of PHP code automatically implies a semicolon; you do not need to have a semicolon terminating the last line of a PHP block. The closing tag for the block will include the immediately trailing newline if one is present.

Example showing the closing tag encompassing the trailing newline

<?php echo "Some text"; ?>
No newline
<?= "But newline now" ?>

     

ENTITY

Some textNo newline
But newline now

Examples of entering and exiting the PHP parser

<?php
    echo "This is a test\n";
?>

<?php echo "This is a test\n" ?>

<?php echo "We omitted the last closing tag\n";

     

[!NOTE] The closing tag of a PHP block at the end of a file is optional, and in some cases omitting it is helpful when using include or require, so unwanted whitespace will not occur at the end of files, and you will still be able to add headers to the response later. It is also handy if you use output buffering, and would not like to see added unwanted whitespace at the end of the parts generated by the included files.

Comments

PHP supports 'C', 'C++' and Unix shell-style (Perl style) comments. For example:

Comments

<?php
    echo "This is a test\n"; // This is a one-line c++ style comment
    /* This is a multi line comment
       yet another line of comment */
    echo "This is yet another test\n";
    echo "One Final Test\n"; # This is a one-line shell-style comment
?>

     

The "one-line" comment styles only comment to the end of the line or the current block of PHP code, whichever comes first. This means that HTML code after // ... ?ENTITY or # ... ?ENTITY WILL be printed: ?ENTITY breaks out of PHP mode and returns to HTML mode, and // or # cannot influence that.

One Line Comments

<h1>This is an <?php # echo 'simple';?> example</h1>
<p>The header above will say 'This is an  example'.</p>

     

'C' style comments end at the first */ encountered. Make sure you don't nest 'C' style comments. It is easy to make this mistake if you are trying to comment out a large block of code.

<?php
 /*
    echo 'This is a test'; /* This comment will cause a problem */
 */
?>

     

Constants

A constant is an identifier (name) for a simple value. As the name suggests, that value cannot change during the execution of the script (except for magic constants, which aren't actually constants). Constants are case-sensitive. By convention, constant identifiers are always uppercase.

[!NOTE] Prior to PHP 8.0.0, constants defined using the define function may be case-insensitive.

[!NOTE] As of PHP 8.5.0, redeclaring an already-defined constant is deprecated.

The name of a constant follows the same rules as any label in PHP. A valid constant name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thusly: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$

It is possible to define constants with reserved or even invalid names, whose value can only be retrieved with the constant function. However, doing so is not recommended.

ENTITY

Valid and invalid constant names

<?php

// Valid constant names
define("FOO",     "something");
define("FOO2",    "something else");
define("FOO_BAR", "something more");

// Invalid constant names
define("2FOO",    "something");

// This is valid, but should be avoided:
// PHP may one day provide a magical constant
// that will break your script
define("__FOO__", "something"); 

    

[!NOTE] For our purposes here, a letter is a-z, A-Z, and the ASCII characters from 128 through 255 (0x80-0xff).

Like ENTITY, the scope of a constant is global. Constants can be accessed from anywhere in a script without regard to scope. For more information on scope, read the manual section on variable scope.

[!NOTE] As of PHP 7.1.0, class constant may declare a visibility of protected or private, making them only available in the hierarchical scope of the class in which it is defined.

Syntax

Constants can be defined using the const keyword, or by using the define-function. While define allows a constant to be defined to an arbitrary expression, the const keyword has restrictions as outlined in the next paragraph. Once a constant is defined, it can never be changed or undefined.

When using the const keyword, only scalar (bool, int, float and string) expressions and constant arrays containing only scalar expressions are accepted. It is possible to define constants as a resource, but it should be avoided, as it can cause unexpected results.

The value of a constant is accessed simply by specifying its name. Unlike variables, a constant is not prepended with a $. It is also possible to use the constant function to read a constant's value if the constant's name is obtained dynamically. Use get_defined_constants to get a list of all defined constants.

[!NOTE] Constants and (global) variables are in a different namespace. This implies that for example ENTITY and $TRUE are generally different.

If an undefined constant is used an Error is thrown. Prior to PHP 8.0.0, undefined constants would be interpreted as a bare word string, i.e. (CONSTANT vs "CONSTANT"). This fallback is deprecated as of PHP 7.2.0, and an error of level E_WARNING is issued when it happens. Prior to PHP 7.2.0, an error of level E_NOTICE has been issued instead. See also the manual entry on why $foo[bar] is wrong (unless bar is a constant). This does not apply to (fully) qualified constants, which will always raise a Error if undefined.

[!NOTE] To check if a constant is set, use the defined function.

These are the differences between constants and variables:

Defining Constants

<?php
define("CONSTANT", "Hello world.");
echo CONSTANT; // outputs "Hello world."
echo Constant; // Emits an Error: Undefined constant "Constant"
               // Prior to PHP 8.0.0, outputs "Constant" and issues a warning.

     

Defining Constants using the const keyword

<?php
// Simple scalar value
const CONSTANT = 'Hello World';

echo CONSTANT . "\n";

// Scalar expression
const ANOTHER_CONST = CONSTANT . '; Goodbye World';
echo ANOTHER_CONST . "\n";

const ANIMALS = array('dog', 'cat', 'bird');
echo ANIMALS[1] . "\n"; // outputs "cat"

// Constant arrays
define('ANIMALS_DEF', array(
    'dog',
    'cat',
    'bird'
));
echo ANIMALS_DEF[1] . "\n"; // outputs "cat"

     

[!NOTE] As opposed to defining constants using define, constants defined using the const keyword must be declared at the top-level scope because they are defined at compile-time. This means that they cannot be declared inside functions, loops, if statements or try/catch blocks.

ENTITY

ENTITY ENTITY
8.5.0 Added support for type casts (e.g. (int), (string)) in constant expressions. Also added support for Closures and first-class callables in constant expressions.

ENTITY

Class Constants

Predefined constants

PHP provides a large number of predefined constants to any script which it runs. Many of these constants, however, are created by various extensions, and will only be present when those extensions are available, either via dynamic loading or because they have been compiled in.

Magic constants

Magic constants are keywords that are replaced with information about their own location in the source code: their file and line, and the function, class, trait, namespace, or property hook enclosing them. Despite their name, they are not actual constants: defined and constant do not recognize them, and a constant of the same name created with define does not affect them. They are case-insensitive. When used outside of the relevant context (e.g. __CLASS__ outside of a class), they are replaced with an empty string.

ENTITY ENTITY
__LINE__ The line number on which it is written.
__FILE__ The full path and filename of the file in which it is written, with symlinks resolved.
__DIR__ The directory of the file, equivalent to dirname(__FILE__). It has no trailing slash unless it is the root directory.
__FUNCTION__ The name of the function in which it is written, including its namespace (e.g. Foo\bar). Inside a method, only the method name. For anonymous functions, a name generated by the engine that includes where the closure was defined (as of PHP 8.4.0; previously {closure}).
__CLASS__ The name of the class in which it is written, including its namespace (e.g. Foo\Bar). Inside a trait, the name of the class using the trait. For anonymous classes, a name generated by the engine. To get the name of the class a method was called on, use static::class.
__TRAIT__ The trait name, including its namespace (e.g. Foo\Bar).
__METHOD__ The class and method name of the method in which it is written (e.g. Foo\Bar::baz). Inside a trait, the trait name is used instead of the class name. Outside of a method, the same as __FUNCTION__.
__PROPERTY__ The name of the property, when used inside a property hook. Available as of PHP 8.4.0.
__NAMESPACE__ The name of the current namespace.

PHP's magic constants

Using magic constants

<?php
namespace App;

function helper()
{
    echo __FUNCTION__, "\n";
    echo __METHOD__, "\n";
}

trait Greets
{
    public function greet()
    {
        echo __CLASS__, "\n";
        echo __TRAIT__, "\n";
        echo __METHOD__, "\n";
        echo __FUNCTION__, "\n";
    }
}

class Greeter
{
    use Greets;
}

helper();
(new Greeter)->greet();
echo __NAMESPACE__, "\n";

    

ENTITY

App\helper
App\helper
App\Greeter
App\Greets
App\Greets::greet
greet
App

ENTITY

::class, get_class, get_called_class, dirname

context

PHP offers various context options and parameters which can be used with all filesystem and stream wrappers. The context is created with stream_context_create. Options are set with stream_context_set_option and parameters with stream_context_set_params.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

ftp

FTP context options

FTP context option listing

ENTITY

Context options for ftp:// and ftps:// transports.

ENTITY

overwrite bool
Allow overwriting of already existing files on remote server. Applies to write mode (uploading) only.

Defaults to ENTITY.

resume_pos int
File offset at which to begin transfer. Applies to read mode (downloading) only.

Defaults to 0 (Beginning of File).

proxy string
Proxy FTP request via http proxy server. Applies to file read operations only. Ex: tcp://squid.example.com:8000.

ENTITY

[!NOTE] Additional context options may be supported by the underlying transport. For ftp:// streams, refer to context options for the tcp:// transport. For ftps:// streams, refer to context options for the ssl:// transport.

ENTITY

???, ???, ???

http

HTTP context options

HTTP context option listing

ENTITY

Context options for http:// and https:// transports.

ENTITY

method string
GET, POST, or any other HTTP method supported by the remote server.

Defaults to GET.

header array or string
Additional headers to be sent during request. Values in this option will override other values (such as User-agent:, Host:, and Authentication:), even when following Location: redirects. Thus it is not recommended to set a Host: header, if follow_location is enabled.

String value should be Key: value pairs delimited by \r\n, e.g. "Content-Type: application/json\r\nConnection: close". Array value should be a list of Key: value pairs, e.g. ["Content-Type: application/json", "Connection: close"].

user_agent string
Value to send with User-Agent: header. This value will only be used if user-agent is not specified in the header context option above.

By default the user_agent ENTITY setting is used.

content string
Additional data to be sent after the headers. Typically used with POST or PUT requests.

proxy string
URI specifying address of proxy server (e.g. tcp://proxy.example.com:5100).

request_fulluri bool
When set to ENTITY, the entire URI will be used when constructing the request (e.g. GET http://www.example.com/path/to/file.html HTTP/1.0). While this is a non-standard request format, some proxy servers require it.

Defaults to ENTITY.

follow_location int
Follow Location header redirects. Set to 0 to disable.

When this option is not set, redirects are only followed for the 300, 301, 302, 303, 307 and 308 response codes. Setting it to 1 is not equivalent: any response carrying a Location header is then followed, whatever its response code.

max_redirects int
The max number of redirects to follow. Value 1 or less means that no redirects are followed.

Defaults to 20.

protocol_version float
HTTP protocol version.

Defaults to 1.1 as of PHP 8.0.0; prior to that version the default was 1.0.

timeout float
Read timeout in seconds, specified by a float (e.g. 10.5).

By default the default_socket_timeout ENTITY setting is used.

ignore_errors bool
Fetch the content even on failure status codes.

Defaults to ENTITY.

uri_parser_class string or null
The class to use for parsing URIs. When ENTITY, the legacy behavior based on parse_url is used. Accepted values are Uri\Rfc3986\Uri (RFC 3986 compliant parser) and Uri\WhatWg\Url (WHATWG URL Standard parser). Custom userland implementations are not supported.

Defaults to ENTITY.

ENTITY

ENTITY ENTITY
8.5.0 The uri_parser_class option was added.

ENTITY

Fetch a page and send POST data

<?php

$postdata = http_build_query(
    [
        'var1' => 'some content',
        'var2' => 'doh',
    ]
);

$opts = [
    'http' => [
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => $postdata,
    ]
];

$context = stream_context_create($opts);

$result = file_get_contents('http://example.com/submit.php', false, $context);

?>

    

Ignore redirects but fetch headers and content

<?php

$url = "http://www.example.org/header.php";

$opts = [
    'http' => [
        'method'        => 'GET',
        'max_redirects' => '0',
        'ignore_errors' => '1',
    ]
];

$context = stream_context_create($opts);
$stream = fopen($url, 'r', false, $context);

// header information as well as meta data
// about the stream
var_dump(stream_get_meta_data($stream));

// actual data at $url
var_dump(stream_get_contents($stream));
fclose($stream);
?>

    

ENTITY

[!NOTE] Additional context options may be supported by the underlying transport For http:// streams, refer to context options for the tcp:// transport. For https:// streams, refer to context options for the ssl:// transport.

[!NOTE] When this stream wrapper follows a redirect, the wrapper_data returned by stream_get_meta_data might not necessarily contain the HTTP status line that actually applies to the content data at index 0.

array (
  'wrapper_data' =>
  array (
    0 => 'HTTP/1.0 301 Moved Permanently',
    1 => 'Cache-Control: no-cache',
    2 => 'Connection: close',
    3 => 'Location: http://example.com/foo.jpg',
    4 => 'HTTP/1.1 200 OK',
    ...

The first request returned a 301 (permanent redirect), so the stream wrapper automatically followed the redirect to get a 200 response (index = 4).

ENTITY

???, ???, ???

parameters

Context parameters

Context parameter listing

ENTITY

These parameters can be set on a context using the stream_context_set_params function.

ENTITY

notification callable
A callable to be called when an event occurs on a stream.

See stream_notification_callback for more details.

phar

Phar context options

Phar context option listing

ENTITY

Context options for phar:// wrapper.

ENTITY

compress int
One of Phar compression constants.

metadata mixed
Phar metadata. See Phar::setMetadata.

ENTITY

???, Phar stream wrapper

socket

Socket context options

Socket context option listing

ENTITY

Socket context options are available for all wrappers that work over sockets, like tcp, http and ftp.

ENTITY

bindto
Used to specify the IP address (either IPv4 or IPv6) and/or the port number that PHP will use to access the network. The syntax is ip:port for IPv4 addresses, and [ip]:port for IPv6 addresses. Setting the IP or the port to 0 will let the system choose the IP and/or port.

[!NOTE] As FTP creates two socket connections during normal operation, the port number cannot be specified using this option.

backlog
Used to limit the number of outstanding connections in the socket's listen queue.

[!NOTE] This is only applicable to stream_socket_server.

ipv6_v6only
Overrides the OS default regarding mapping IPv4 into IPv6.

[!NOTE] This is important in particular when trying to listen on IPv4 addresses separately while there exists a binding on [::].

This is only applicable to stream_socket_server.

so_reuseport
Allows multiple bindings to a same ip:port pair, even from separate processes.

[!NOTE] This is only applicable to stream_socket_server.

so_broadcast
Enables sending and receiving data to/from broadcast addresses.

[!NOTE] This is only applicable to stream_socket_server.

tcp_nodelay
Setting this option to ENTITY will set SOL_TCP,NO_DELAY=1 appropriately, thus disabling the TCP Nagle algorithm.

ENTITY

ENTITY ENTITY
7.1.0 Added tcp_nodelay.
7.0.1 Added ipv6_v6only.

ENTITY

Basic bindto usage example

<?php
// connect to the internet using the '192.168.0.100' IP
$opts = array(
    'socket' => array(
        'bindto' => '192.168.0.100:0',
    ),
);


// connect to the internet using the '192.168.0.100' IP and port '7000'
$opts = array(
    'socket' => array(
        'bindto' => '192.168.0.100:7000',
    ),
);


// connect to the internet using the '2001:db8::1' IPv6 address
// and port '7000'
$opts = array(
    'socket' => array(
        'bindto' => '[2001:db8::1]:7000',
    ),
);


// connect to the internet using port '7000'
$opts = array(
    'socket' => array(
        'bindto' => '0:7000',
    ),
);


// create the context...
$context = stream_context_create($opts);

// ...and use it to fetch the data
echo file_get_contents('http://www.example.com', false, $context);

?>

    

ssl

SSL context options

SSL context option listing

ENTITY

Context options for ssl:// and tls:// transports.

ENTITY

peer_name string
Peer name to be used. If this value is not set, then the name is guessed based on the hostname used when opening the stream.

verify_peer bool
Require verification of SSL certificate used.

Defaults to ENTITY.

verify_peer_name bool
Require verification of peer name.

Defaults to ENTITY.

allow_self_signed bool
Allow self-signed certificates. Requires verify_peer.

Defaults to ENTITY

cafile string
Location of Certificate Authority file on local filesystem which should be used with the verify_peer context option to authenticate the identity of the remote peer.

capath string
If cafile is not specified or if the certificate is not found there, the directory pointed to by capath is searched for a suitable certificate. capath must be a correctly hashed certificate directory.

local_cert string
Path to local certificate file on filesystem. It must be a PEM encoded file which contains your certificate and private key. It can optionally contain the certificate chain of issuers. The private key also may be contained in a separate file specified by local_pk.

local_pk string
Path to local private key file on filesystem in case of separate files for certificate (local_cert) and private key.

passphrase string
Passphrase with which your local_cert file was encoded.

verify_depth int
Abort if the certificate chain is too deep.

Defaults to no verification.

ciphers string
Sets the list of available ciphers. The format of the string is described in ciphers(1).

Defaults to DEFAULT.

capture_peer_cert bool
If set to ENTITY a peer_certificate context option will be created containing the peer certificate.

capture_peer_cert_chain bool
If set to ENTITY a peer_certificate_chain context option will be created containing the certificate chain.

SNI_enabled bool
If set to ENTITY server name indication will be enabled. Enabling SNI allows multiple certificates on the same IP address.

SNI_server_certs array
An array of server names and their corresponding certificates to be used for SNI. The keys are the server names and the values are the paths to the certificate files on the local filesystem. The certificate files must be PEM encoded and contain both the certificate and private key.

Available as of PHP 5.6.0.

alpn_protocols array
An array of application layer protocol names to be used for ALPN (Application-Layer Protocol Negotiation). The values are the protocol names as strings (e.g. "http/1.1", "h2").

Available as of PHP 7.0.0 and OpenSSL 1.0.2.

no_ticket bool
If set, disable TLS session tickets. This can help to enhance security by providing Perfect Forward Secrecy (PFS).

Available as of PHP 5.3.6.

disable_compression bool
If set, disable TLS compression. This can help mitigate the CRIME attack vector.

peer_fingerprint string | array
Aborts when the remote certificate digest doesn't match the specified hash.

When a string is used, the length will determine which hashing algorithm is applied, either "md5" (32) or "sha1" (40).

When an array is used, the keys indicate the hashing algorithm name and each corresponding value is the expected digest.

security_level int
Sets the security level. If not specified the library default security level is used. The security levels are described in SSL_CTX_get_security_level(3).

Available as of PHP 7.2.0 and OpenSSL 1.1.0.

min_proto_version int
Sets the minimum protocol version allowed. If not specified the library default minimum protocol version is used. The protocol versions are described in SSL_CTX_set_min_proto_version(3).

Available as of PHP 7.3.0 and OpenSSL 1.1.0.

max_proto_version int
Sets the maximum protocol version allowed. If not specified the library default maximum protocol version is used. The protocol versions are described in SSL_CTX_set_max_proto_version(3).

Available as of PHP 7.3.0 and OpenSSL 1.1.0.

ENTITY

ENTITY ENTITY
7.3.0 Added min_proto_version and max_proto_version. Requires OpenSSL ENTITY= 1.1.0.
7.2.0 Added security_level. Requires OpenSSL ENTITY= 1.1.0.
7.0.0 Added alpn_protocols. Requires OpenSSL ENTITY= 1.0.2.
5.6.0 Added SNI_server_certs.
5.3.6 Added no_ticket.

ENTITY

[!NOTE] Because ssl:// is the underlying transport for the https:// and ftps:// wrappers, any context options which apply to ssl:// also apply to https:// and ftps://.

[!NOTE] For SNI (Server Name Indication) to be available, then PHP must be compiled with OpenSSL 0.9.8j or greater. Use the OPENSSL_TLSEXT_SERVER_NAME to determine whether SNI is supported.

ENTITY

zip

Zip context options

Zip context option listing

ENTITY

Zip context options are available for zip wrappers.

ENTITY

password
Used to specify password used for encrypted archive.

ENTITY

ENTITY ENTITY
7.2.0, PECL zip 1.14.0 Added password.

ENTITY

Basic password usage example

<?php
// Read encrypted archive
$opts = array(
    'zip' => array(
        'password' => 'secret',
    ),
);
// create the context...
$context = stream_context_create($opts);

// ...and use it to fetch the data
echo file_get_contents('zip://test.zip#test.txt', false, $context);

?>

    

zlib

Zlib context options

Zlib context option listing

ENTITY

Zlib context options are available for zlib wrappers.

ENTITY

level
Used to specify the compression level (0 - 9).

ENTITY

ENTITY ENTITY
7.3.0 level has been added.

Control Structures

Introduction

Any PHP script is built out of a series of statements. A statement can be an assignment, a function call, a loop, a conditional statement or even a statement that does nothing (an empty statement). Statements usually end with a semicolon. In addition, statements can be grouped into a statement-group by encapsulating a group of statements with curly braces. A statement-group is a statement by itself as well. The various statement types are described in this chapter.

ENTITY

The following are also considered language constructs even though they are referenced under functions in the manual.

list, array, echo, eval, print

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

Alternative syntax for control structures

PHP offers an alternative syntax for some of its control structures; namely, if, while, for, foreach, switch, and declare. In each case, the basic form of the alternate syntax is to change the opening brace to a colon (:) and the closing brace to endif;, endwhile;, endfor;, endforeach;, endswitch;, or enddeclare;, respectively.

<?php
$a = 5;
if ($a == 5): ?>
A is equal to 5
<?php endif; ?>

   

ENTITY

A is equal to 5

In the above example, the HTML block "A is equal to 5" is nested within an if statement written in the alternative syntax. The HTML block would be displayed only if $a is equal to 5.

The alternative syntax applies to else and elseif as well. The following is an if structure with elseif and else in the alternative format:

<?php
$a = 5;
if ($a == 5):
    echo "a equals 5";
    echo "...";
elseif ($a == 6):
    echo "a equals 6";
    echo "!!!";
else:
    echo "a is neither 5 nor 6";
endif;

   

ENTITY

a equals 5...

[!NOTE] Mixing syntaxes in the same control block is not supported.

[!WARNING] Any output (including whitespace) between a switch statement and the first case will result in a syntax error. For example, this is invalid:

<?php
$foo = 1;
switch ($foo): ?>
    <?php case 1: ?>
    Foo is 1
<?php endswitch; ?>

   

ENTITY

Parse error: syntax error, unexpected T_INLINE_HTML "    ", expecting "endswitch" or "case" or "default" in script on line 4

Whereas this is valid, as the trailing newline after the switch statement is considered part of the closing ?ENTITY and hence nothing is output between the switch and case:

<?php
$foo = 1;
switch ($foo): ?>
<?php case 1: ?>
    Foo is 1
<?php endswitch; ?>

   

ENTITY

    Foo is 1

See also while, for, and if for further examples.

break

break ends execution of the current for, foreach, while, do-while or switch structure.

break accepts an optional numeric argument which tells it how many nested enclosing structures are to be broken out of. The default value is 1, only the immediate enclosing structure is broken out of.

<?php
$arr = array('one', 'two', 'three', 'four', 'stop', 'five');
foreach ($arr as $val) {
    if ($val == 'stop') {
        break;    /* You could also write 'break 1;' here. */
    }
    echo "$val\n";
}

   

ENTITY

one
two
three
four

Using the optional argument:

<?php
$i = 0;
while (++$i) {
    switch ($i) {
        case 5:
            echo "At 5\n";
            break 1;  /* Exit only the switch. */
        case 10:
            echo "At 10; quitting\n";
            break 2;  /* Exit the switch and the while. */
        default:
            break;
    }
    echo "$i\n";
}

   

ENTITY

1
2
3
4
At 5
5
6
7
8
9
At 10; quitting

continue

continue is used within looping structures to skip the rest of the current loop iteration and continue execution at the condition evaluation and then the beginning of the next iteration.

[!NOTE] In PHP the switch statement is considered a looping structure for the purposes of continue. continue behaves like break (when no arguments are passed) but will raise a warning as this is likely to be a mistake. If a switch is inside a loop, continue 2 will continue with the next iteration of the outer loop.

continue accepts an optional numeric argument which tells it how many levels of enclosing loops it should skip to the end of. The default value is 1, thus skipping to the end of the current loop.

<?php
$arr = ['zero', 'one', 'two', 'three', 'four', 'five', 'six'];
foreach ($arr as $key => $value) {
    if (0 === ($key % 2)) { // skip members with even key
        continue;
    }
    echo $value . "\n";
}

   

ENTITY

one
three
five
<?php
$i = 0;
while ($i++ < 5) {
    echo "Outer\n";
    while (1) {
        echo "Middle\n";
        while (1) {
            echo "Inner\n";
            continue 3;
        }
        echo "This never gets output.\n";
    }
    echo "Neither does this.\n";
}

   

ENTITY

Outer
Middle
Inner
Outer
Middle
Inner
Outer
Middle
Inner
Outer
Middle
Inner
Outer
Middle
Inner
ENTITY ENTITY
7.3.0 continue within a switch that is attempting to act like a break statement for the switch will trigger an E_WARNING.

Changelog for continue

declare

The declare construct is used to set execution directives for a block of code. The syntax of declare is similar to the syntax of other flow control constructs:

declare (directive)
    statement

The directive section allows the behavior of the declare block to be set. Currently only three directives are recognized: ticks, encoding, strict_types

As directives are handled as the file is being compiled, only literals may be given as directive values. Variables and constants cannot be used. To illustrate:

<?php
// This is valid:
declare(ticks=1);

// This is invalid:
const TICK_VALUE = 1;
declare(ticks=TICK_VALUE);

   

The statement part of the declare block will be executed - how it is executed and what side effects occur during execution may depend on the directive set in the directive block.

The declare construct can also be used in the global scope, affecting all code following it (however if the file with declare was included then it does not affect the parent file).

<?php
// these are the same:

// you can use this:
declare(ticks=1) {
    // entire script here
}

// or you can use this:
declare(ticks=1);
// entire script here

   

Ticks

A tick is an event that occurs for every N low-level tickable statements executed by the parser within the declare block. The value for N is specified using ticks=N within the declare block's directive section.

Not all statements are tickable. Typically, condition expressions and argument expressions are not tickable.

The event(s) that occur on each tick are specified using the register_tick_function. See the example below for more details. Note that more than one event can occur for each tick.

Tick usage example

<?php

declare(ticks=1);

// A function called on each tick event
function tick_handler()
{
    echo "tick_handler() called\n";
}

register_tick_function('tick_handler'); // causes a tick event

$a = 1; // causes a tick event

if ($a > 0) {
    $a += 2; // causes a tick event
    print $a . "\n"; // causes a tick event
}

   

ENTITY

tick_handler() called
tick_handler() called
tick_handler() called
3
tick_handler() called

See also register_tick_function and unregister_tick_function.

Encoding

A script's encoding can be specified per-script using the encoding directive.

Declaring an encoding for the script

<?php
declare(encoding='ISO-8859-1');
// code here

    

[!CAUTION] When combined with namespaces, the only legal syntax for declare is declare(encoding='...'); where ... is the encoding value. declare(encoding='...') {} will result in a parse error when combined with namespaces.

See also zend.script_encoding.

do-while

do-while loops are very similar to while loops, except the truth expression is checked at the end of each iteration instead of at the beginning. The main difference from regular while loops is that the first iteration of a do-while loop is guaranteed to run (the truth expression is only checked at the end of the iteration), whereas it may not necessarily run with a regular while loop (the truth expression is checked at the beginning of each iteration; if it evaluates to ENTITY right from the beginning, the loop execution would end immediately).

There is just one syntax for do-while loops:

<?php
$i = 0;
do {
    echo $i;
} while ($i > 0);

   

ENTITY

0

The above loop would run one time exactly, since after the first iteration, when the truth expression is checked, it evaluates to ENTITY ($i is not bigger than 0) and the loop execution ends.

Advanced C users may be familiar with a different usage of the do-while loop, to allow stopping execution in the middle of code blocks, by encapsulating them with do-while (0), and using the break statement. The following code fragment demonstrates this:

<?php
$i = 50;
$factor = 0.5;
$minimum_limit = 20;
do {
    if ($i < 5) {
        echo "i is not big enough\n";
        break;
    }
    $i *= $factor;
    if ($i < $minimum_limit) {
        echo "i is less than minimum limit after factor\n";
        break;
    }
    echo $i ." is ok\n";

    /* process i */

} while (0);

   

ENTITY

25 is ok

It is possible to use the goto operator instead of this hack.

else

Often you'd want to execute a statement if a certain condition is met, and a different statement if the condition is not met. This is what else is for. else extends an if statement to execute a statement in case the expression in the if statement evaluates to ENTITY. For example, the following code would display a is greater than b if $a is greater than $b, and a is NOT greater than b otherwise:

<?php
$a = 3;
$b = 5;
if ($a > $b) {
  echo "a is greater than b\n";
} else {
  echo "a is NOT greater than b\n";
}

   

ENTITY

a is NOT greater than b

The else statement is only executed if the if expression evaluated to ENTITY, and if there were any elseif expressions - only if they evaluated to ENTITY as well (see elseif).

[!NOTE] In case of nested if-else statements, an else is always associated with the nearest if.

<?php
$a = false;
$b = true;
if ($a)
    if ($b)
        echo "b";
else
    echo "c";

    

ENTITY

Despite the indentation (which does not matter for PHP), the else is associated with the if ($b), so the example does not produce any output. While relying on this behavior is valid, it is recommended to avoid it by using curly braces to resolve potential ambiguities.

elseif/else if

elseif, as its name suggests, is a combination of if and else. Like else, it extends an if statement to execute a different statement in case the original if expression evaluates to ENTITY. However, unlike else, it will execute that alternative expression only if the elseif conditional expression evaluates to ENTITY. For example, the following code would display a is bigger than b, a equal to b or a is smaller than b:

<?php
$a = 1;
$b = 1;
if ($a > $b) {
    echo "a is bigger than b";
} elseif ($a == $b) {
    echo "a is equal to b";
} else {
    echo "a is smaller than b";
}

   

ENTITY

a is equal to b

There may be several elseifs within the same if statement. The first elseif expression (if any) that evaluates to ENTITY would be executed. In PHP, it's possible to write else if (in two words) and the behavior would be identical to that of elseif (in a single word). The syntactic meaning is slightly different (the same behavior as C) but the bottom line is that both would result in exactly the same behavior.

The elseif statement is only executed if the preceding if expression and any preceding elseif expressions evaluated to ENTITY, and the current elseif expression evaluated to ENTITY.

[!NOTE] Note that elseif and else if will only be considered exactly the same when using curly brackets as in the above example. When using a colon to define if/elseif conditions, the use of elseif in a single word becomes necessary. PHP will fail with a parse error if else if is split into two words.

<?php
$a = 3;
$b = 1;

/* Incorrect Method: */
if ($a > $b):
    echo $a." is greater than ".$b;
else if ($a == $b): // Will not compile.
    echo "The above line causes a parse error.";
endif;

   

ENTITY

Parse error: syntax error, unexpected token "if", expecting ":" in script on line 8
<?php
$a = 3;
$b = 1;

/* Correct Method: */
if ($a > $b):
    echo $a." is greater than ".$b;
elseif ($a == $b): // Note the combination of the words.
    echo $a." equals ".$b;
else:
    echo $a." is neither greater than or equal to ".$b;
endif;

   

ENTITY

3 is greater than 1

finally

A ENTITY block may also be specified after or instead of ENTITY blocks. Code within the ENTITY block will always be executed after the ENTITY and ENTITY blocks, even if a ENTITY or ENTITY statement is encountered, or if a Throwable error is not caught or is rethrown. It will be executed prior to resuming the normal execution flow. The only exception to this rule is when the script is terminated abruptly, such as by a call to exit or by a fatal error (for example, when the maximum execution time is exceeded).

Throwable error handling with a ENTITY block

<?php
function inverse($x) {
    return 1/$x;
}

try {
    echo inverse(5) . "\n";
} catch (DivisionByZeroError $e) {
    echo 'Caught error: ', $e->getMessage(), "\n";
} finally {
    echo "First finally.\n";
}

try {
    echo inverse(0) . "\n";
} catch (DivisionByZeroError $e) {
    echo 'Caught error: ', $e->getMessage(), "\n";
} finally {
    echo "Second finally.\n";
}

// Continue execution
echo "Hello World\n";

  

ENTITY

0.2
First finally.
Caught error: Division by zero
Second finally.
Hello World

When the call stack is unwound after a Throwable error has been thrown, all ENTITY blocks it encounters along the way will be executed. In other words, nested ENTITY blocks are executed even if the Throwable error is not caught by an adjacent ENTITY block.

All ENTITY blocks will be executed

   
<?php
try {
    try {
        throw new Exception();
    } finally {
        echo "Inner finally\n";
    }
} catch (Exception $e) {
} finally {
    echo "Outer finally\n";
}

  

ENTITY

Inner finally
Outer finally

Interaction between a ENTITY block and a ENTITY statement

One notable interaction is between the ENTITY block and a ENTITY statement. If a ENTITY statement is encountered inside either the ENTITY or the ENTITY block, the ENTITY block will still be executed. Moreover, the ENTITY statement is evaluated when encountered, but the result will be returned after the ENTITY block is executed. Additionally, if the ENTITY block also contains a ENTITY statement, the value from the ENTITY block is returned.

Interaction between ENTITY in ENTITY block and a previous ENTITY

<?php
function testReturnTry() {
    try {
        echo 'Within try', "\n";
        return 'try';
    } finally {
        echo 'Within finally', "\n";
        return 'finally';
    }
}

function testReturnCatch() {
    try {
        throw new Exception('foo');
    } catch (Exception $e) {
        echo 'Within catch', "\n";
        return 'catch';
    } finally {
        echo 'Within finally', "\n";
        return 'finally';
    }
}

echo testReturnTry(), "\n";
echo testReturnCatch(), "\n";


   

ENTITY

Within try
Within finally
finally
Within catch
Within finally
finally

Interaction between the ENTITY block and ENTITY

<?php
function testReturnTry() {
    try {
        return 'try';
    } finally {
        echo 'finally ';
    }
}

function testReturnCatch() {
    try {
        throw new Exception('foo');
    } catch (Exception $e) {
        return 'catch';
    } finally {
        echo 'finally ';
    }
}

echo testReturnTry(), "\n";
echo testReturnCatch(), "\n";

   

ENTITY

finally try
finally catch

Interaction between a ENTITY block and an exception thrown in a ENTITY block

If both the ENTITY block and the ENTITY block throw an exception, the exception thrown from the ENTITY block is the one that is propagated, and the exception thrown from the ENTITY block will be used as its previous exception.

Exception in try and in finally

<?php

try {
    try {
        throw new Exception(message: 'Third', previous: new Exception('Fourth'));
    } finally {
        throw new Exception(message: 'First', previous: new Exception('Second'));
    }
} catch (Exception $e) {
    var_dump(
        $e->getMessage(),
        $e->getPrevious()->getMessage(),
        $e->getPrevious()->getPrevious()->getMessage(),
        $e->getPrevious()->getPrevious()->getPrevious()->getMessage(),
    );
}

   

ENTITY

string(5) "First"
string(6) "Second"
string(5) "Third"
string(6) "Fourth"

Behaviour of a ENTITY block in a Generator

If, during the traversal of a generator, a Throwable error is thrown, the ENTITY block within the generator will be executed, as it is the previous element of the call stack.

ENTITY block being run when an Exception has been thrown

    
<?php
function generate()
{
    try {
        yield 1;
        yield 2;
    } catch (Exception $e) {
        echo 'catch';
    } finally {
        echo "finally\n";
    }
}

try {
    foreach (generate() as $i) {
        echo $i, "\n";
        throw new Exception();
    }
} catch (Exception $e) {
    echo 'outer catch';
}

   

ENTITY

1
finally
outer catch

It is possible to ENTITY within a ENTITY block, but if a Throwable error occurs and is not caught within the ENTITY, a Cannot yield from finally in a force-closed generator Error is thrown.

Error when ENTITYing in a ENTITY block when an Exception has been thrown

<?php
function generate()
{
    try {
        yield 1;
        yield 2;
    } catch (Exception $e) {
        echo 'catch';
    } finally {
        echo "finally\n";
        yield 3;
    }
}

try {
    foreach (generate() as $i) {
        echo $i, "\n";
        throw new Exception();
    }
} catch (Exception $e) {
    echo 'outer catch';
}

   

ENTITY

1
finally

Fatal error: Uncaught Exception in /in/GbFmu:19
Stack trace:
#0 {main}

Next Error: Cannot yield from finally in a force-closed generator in /in/GbFmu:12
Stack trace:
#0 /in/GbFmu(19): generate()
#1 {main}
  thrown in /in/GbFmu on line 12

Interaction between a ENTITY block and a call to exit

When exit is called within a ENTITY or a ENTITY block, all ENTITY blocks are skipped.

Interaction between a ENTITY block and exit called in a ENTITY block

<?php
try {
    echo 'quit';
    exit(0);
} finally {
    echo 'finally';
}

   

ENTITY

quit

Interaction between a ENTITY block and exit called in a ENTITY block

<?php
try {
    throw new Exception('foo');
} catch (Exception $e) {
    echo 'catch';
    exit(0);
} finally {
    echo 'finally ';
}

   

ENTITY

catch

All ENTITY blocks are skipped when exit is called

<?php
try {
    try {
        echo 'quit';
        exit(0);
    } finally {
        echo 'inner finally ';
    }
} finally {
    echo 'outer finally';
}

   

ENTITY

quit

When exit is called within a ENTITY block, all outer ENTITY blocks are skipped.

Skipping an outer ENTITY block by calling exit

<?php
try {
    try {
        echo 'try', "\n";
    } finally {
        echo 'inner finally ';
        exit(0);
    }
} finally {
    echo 'outer finally';
}

   

ENTITY

try
inner finally

Edge case of calling exit in a ENTITY over a generator

This one edge case behaviour is highly dependent on which version of PHP the code is executed with.

<?php
function generate()
{
    try {
        yield 1;
        yield 2;
    } catch (Exception $e) {
        echo 'catch';
    } finally {
        echo "inner finally\n";
    }
}

try {
    foreach (generate() as $i) {
        echo $i, "\n";
        exit(0);
    }
} finally {
    echo "outer finally\n";
}

    

Output of the above example prior to PHP 7.1.14, in PHP 7.2.0 and 7.2.1, and as of PHP 8.0.0

1
inner finally

Output of the above example as of PHP 7.1.14 and 7.2.2, and prior to PHP 8.0.0

1

for

for loops are the most complex loops in PHP. They behave like their C counterparts. The syntax of a for loop is:

for (expr1; expr2; expr3)
    statement

The first expression (expr1) is evaluated (executed) once unconditionally at the beginning of the loop.

At the beginning of each iteration, expr2 is evaluated. If it evaluates to ENTITY, the loop continues and the nested statement(s) are executed. If it evaluates to ENTITY, the execution of the loop ends.

At the end of each iteration, expr3 is evaluated (executed).

Each of the expressions can be empty or contain multiple expressions separated by commas. In expr2, all expressions separated by a comma are evaluated but the result is taken from the last part. expr2 being empty means the loop should be run indefinitely (PHP implicitly considers it as ENTITY, like C). This may not be as useless as you might think, since often you'd want to end the loop using a conditional break statement instead of using the for truth expression.

Consider the following examples. All of them display the numbers 1 through 10:

<?php
for ($i = 1; $i <= 10; $i++) {
    echo $i . " ";
}

   

ENTITY

1 2 3 4 5 6 7 8 9 10
<?php
for ($i = 1; ; $i++) {
    if ($i > 10) {
        break;
    }
    echo $i . " ";
}

   

ENTITY

1 2 3 4 5 6 7 8 9 10
<?php
$i = 1;
for (; ; ) {
    if ($i > 10) {
        break;
    }
    echo $i . " ";
    $i++;
}

   

ENTITY

1 2 3 4 5 6 7 8 9 10
<?php
for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i . " ", $i++);

   

ENTITY

1 2 3 4 5 6 7 8 9 10

Of course, the first example appears to be the nicest one (or perhaps the fourth), but you may find that being able to use empty expressions in for loops comes in handy on many occasions.

PHP also supports the alternate "colon syntax" for for loops.

for (expr1; expr2; expr3):
    statement
    ...
endfor;

Expressions expr2 and expr3 are evaluated every iteration. It's advisable to use simple expressions in these places to avoid performance issues. For example, if the number of iterations is known in advance, it is better to use a variable instead of a function call in expr2:

<?php

$people = ['Kalle', 'Pierre'];

// Bad practice: calling a function on every iteration
for($i = 0; $i < getIterationCount($people); ++$i) {
    $people[$i] .= ' is cool';
}

// Good practice: storing the count in a variable
for($i = 0, $peopleCount = getIterationCount($people); $i < $peopleCount; ++$i) {
    $people[$i] .= ' is cool';
}


   

In the example above, the function is called on every iteration of the first loop, even though it always returns the same value. Storing that value in a variable, as the second loop does, calls the function once. Note that the number of iterations is then fixed: if the array is modified inside the loop, the stored value no longer reflects its size.

[!NOTE] The size of an array is stored with the array, which means that calling the built-in function count does not require counting the elements and does not cause performance issues. This does not apply to COUNT_RECURSIVE, which walks the whole array. Care should also be taken when using count on objects implementing Countable, as such calls can be more expensive.

[!NOTE] The for loop is not the recommended way to iterate over arrays. The ENTITY loop is specifically designed for this purpose and is usually more convenient.

foreach

The foreach construct provides an easy way to iterate over arrays and objects. foreach will issue an error when used with a variable containing a different data type or with an uninitialized variable.

foreach can optionally get the key of each element:

foreach (iterable_expression as $value) {
    statement_list
}

foreach (iterable_expression as $key => $value) {
    statement_list
}

The first form traverses the value given by iterable_expression. On each iteration, the value of the current element is assigned to $value.

The second form will additionally assign the current element's key to the $key variable on each iteration.

Note that foreach does not modify the internal array pointer, which is used by functions such as current and key.

By default, an object is traversed over the properties that are visible from the current scope. It is possible to customize object iteration.

Common foreach usages

<?php

echo "Value only\n";
$array = [1, 2, 3, 17];

foreach ($array as $value) {
    echo "Current element of \$array: $value.\n";
}

echo "\n\nKey and value:\n";
$array = [
    "one" => 1,
    "two" => 2,
    "three" => 3,
    "seventeen" => 17
];

foreach ($array as $key => $value) {
    echo "Key: $key => Value: $value\n";
}

echo "\n\nMulti-dimensional key-value arrays:\n";
$grid = [];
$grid[0][0] = "a";
$grid[0][1] = "b";
$grid[1][0] = "y";
$grid[1][1] = "z";

foreach ($grid as $y => $row) {
    foreach ($row as $x => $value) {
        echo "Value at position x=$x and y=$y: $value\n";
    }
}

echo "\n\nDynamic arrays:\n";
foreach (range(1, 5) as $value) {
    echo "$value\n";
}

  

ENTITY

Value only
Current element of $array: 1.
Current element of $array: 2.
Current element of $array: 3.
Current element of $array: 17.


Key and value:
Key: one => Value: 1
Key: two => Value: 2
Key: three => Value: 3
Key: seventeen => Value: 17


Multi-dimensional key-value arrays:
Value at position x=0 and y=0: a
Value at position x=1 and y=0: b
Value at position x=0 and y=1: y
Value at position x=1 and y=1: z


Dynamic arrays:
1
2
3
4
5

[!NOTE] foreach does not support the ability to suppress error messages using the @.

Unpacking nested arrays

It is possible to iterate over an array of arrays and unpack the nested array into loop variables by using either array destructuring via [] or by using the list language construct as the value.

[!NOTE] Please note that array destructuring via [] is only possible as of PHP 7.1.0.

In both of the following examples $a will be set to the first element of the nested array and $b will contain the second element:

<?php
$array = [
    [1, 2],
    [3, 4],
];

foreach ($array as [$a, $b]) {
    echo "A: $a; B: $b\n";
}

foreach ($array as list($a, $b)) {
    echo "A: $a; B: $b\n";
}

    

ENTITY

A: 1; B: 2
A: 3; B: 4
A: 1; B: 2
A: 3; B: 4

When providing fewer variables than there are elements in the array, the remaining elements will be ignored. Similarly, elements can be skipped over by using a comma:

<?php
$array = [
    [1, 2, 5],
    [3, 4, 6],
];

foreach ($array as [$a, $b]) {
    // Note that there is no $c here.
    echo "$a $b\n";
}

foreach ($array as [, , $c]) {
    // Skipping over $a and $b
    echo "$c\n";
}

    

ENTITY

1 2
3 4
5
6

A notice will be generated if there aren't enough array elements to fill the list:

<?php
$array = [
    [1, 2],
    [3, 4],
];

foreach ($array as [$a, $b, $c]) {
    echo "A: $a; B: $b; C: $c\n";
}

    

ENTITY

Notice: Undefined offset: 2 in example.php on line 7
A: 1; B: 2; C:

Notice: Undefined offset: 2 in example.php on line 7
A: 3; B: 4; C:

foreach and references

It is possible to directly modify array elements within a loop by preceding $value with ENTITY. In that case the value will be assigned by reference.

<?php
$arr = [1, 2, 3, 4];
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now [2, 4, 6, 8]
var_dump($arr);
unset($value); // break the reference with the last element

    

ENTITY

array(4) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  &int(8)
}

[!WARNING] A reference to the $value of the last array element remains even after the foreach loop. It is recommended to destroy it using unset. Otherwise, the following behavior will occur:

<?php
$arr = [1, 2, 3, 4];
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now [2, 4, 6, 8]
var_dump($arr);

// without an unset($value), $value is still a reference to the last item: $arr[3]

echo "\nAnother loop:\n";
foreach ($arr as $key => $value) {
    // $arr[3] will be updated with each value from $arr...
    echo "{$key} => {$value}\n";
}
// ...until ultimately the second-to-last value is copied onto the last value
var_dump($arr);

    

ENTITY

array(4) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  &int(8)
}

Another loop:
0 => 2
1 => 4
2 => 6
3 => 6
array(4) {
  [0]=>
  int(2)
  [1]=>
  int(4)
  [2]=>
  int(6)
  [3]=>
  &int(6)
}

Iterate a constant array's values by reference

<?php
foreach ([1, 2, 3, 4] as &$value) {
    $value = $value * 2;
    echo $value . "\n";
}

   

ENTITY

2
4
6
8

ENTITY

array

Traversable

iterable

list

goto

What's the worse thing that could happen if you use goto?

The goto operator can be used to jump to another section in the program. The target point is specified by a case-sensitive label followed by a colon, and the instruction is given as goto followed by the desired target label. This is not a full unrestricted goto. The target label must be within the same file and context, meaning that you cannot jump out of a function or method, nor can you jump into one. You also cannot jump into any sort of loop or switch structure. You may jump out of these, and a common use is to use a goto in place of a multi-level break.

goto example

<?php
goto a;
echo 'Foo';

a:
echo 'Bar';

   

ENTITY

Bar

goto loop example

<?php
for ($i = 0, $j = 50; $i < 100; $i++) {
    while ($j--) {
        if ($j == 17) {
            goto end;
        }
    }
}
echo "i = $i";
end:
echo 'j hit 17';

   

ENTITY

j hit 17

This will not work

<?php
goto loop;
for ($i = 0, $j = 50; $i < 100; $i++) {
    while ($j--) {
        loop:
    }
}
echo "$i = $i";

   

ENTITY

Fatal error: 'goto' into loop or switch statement is disallowed in script on line 2

if

The if construct is one of the most important features of many languages, PHP included. It allows for conditional execution of code fragments. PHP features an if structure that is similar to that of C:

if (expr)
  statement

As described in the section about expressions, <expression> is evaluated to its Boolean value. If <expression> evaluates to ENTITY, PHP will execute <statement>, and if it evaluates to ENTITY - it'll ignore it. More information about what values evaluate to ENTITY can be found in the 'Converting to boolean' section.

The following example would display a is bigger than b if $a is bigger than $b:

<?php
$a = 3;
$b = 1;
if ($a > $b)
  echo "a is bigger than b\n";

   

ENTITY

a is bigger than b

Often you'd want to have more than one statement to be executed conditionally. Of course, there's no need to wrap each statement with an if clause. Instead, you can group several statements into a statement group. For example, this code would display a is bigger than b if $a is bigger than $b, and would then assign the value of $a into $b:

<?php
$a = 3;
$b = 1;
if ($a > $b) {
  echo "a is bigger than b\n";
  $b = $a;
}
var_dump($b);

   

ENTITY

a is bigger than b
int(3)

If statements can be nested infinitely within other if statements, which provides you with complete flexibility for conditional execution of the various parts of your program.

include_once

The include_once expression includes and evaluates the specified file during the execution of the script. This behavior is similar to the include expression, with the only difference being that if the code from a file has already been included, it will not be included again, and include_once returns ENTITY. As the name suggests, the file will be included just once.

include_once may be used in cases where the same file might be included and evaluated more than once during a particular execution of a script, so in this case it may help avoid problems such as function redefinitions, variable value reassignments, etc.

See the include documentation for information about how this function works.

include

The include expression includes and evaluates the specified file.

The documentation below also applies to require.

Files are included based on the file path given or, if none is given, the include_path specified. If the file isn't found in the include_path, include will finally check in the calling script's own directory and the current working directory before failing. The include construct will emit an E_WARNING if it cannot find a file; this is different behavior from require, which will emit an E_ERROR.

Note that both include and require raise additional E_WARNINGs, if the file cannot be accessed, before raising the final E_WARNING or E_ERROR, respectively.

If a path is defined — whether absolute (starting with a drive letter or \ on Windows, or / on Unix/Linux systems) or relative to the current directory (starting with . or ..) — the include_path will be ignored altogether. For example, if a filename begins with ../, the parser will look in the parent directory to find the requested file.

For more information on how PHP handles including files and the include path, see the documentation for include_path.

When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.

Basic include example

vars.php
<?php

$color = 'green';
$fruit = 'apple';

?>

test.php
<?php

echo "A $color $fruit"; // A

include 'vars.php';

echo "A $color $fruit"; // A green apple

?>

   

If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function. An exception to this rule is magic constants which are evaluated by the parser before the include occurs.

Including within functions

<?php

function foo()
{
    global $color;

    include 'vars.php';

    echo "A $color $fruit";
}

/* vars.php is in the scope of foo() so     *
* $fruit is NOT available outside of this  *
* scope.  $color is because we declared it *
* as global.                               */

foo();                    // A green apple
echo "A $color $fruit";   // A green

   

When a file is included, parsing drops out of PHP mode and into HTML mode at the beginning of the target file, and resumes again at the end. For this reason, any code inside the target file which should be executed as PHP code must be enclosed within valid PHP start and end tags.

If "URL include wrappers" are enabled in PHP, you can specify the file to be included using a URL (via HTTP or other supported wrapper - see ??? for a list of protocols) instead of a local pathname. If the target server interprets the target file as PHP code, variables may be passed to the included file using a URL request string as used with HTTP GET. This is not strictly speaking the same thing as including the file and having it inherit the parent file's variable scope; the script is actually being run on the remote server and the result is then being included into the local script.

include through HTTP

<?php

/* This example assumes that www.example.com is configured to parse .php
* files and not .txt files. Also, 'Works' here means that the variables
* $foo and $bar are available within the included file. */

// Won't work; file.txt wasn't handled by www.example.com as PHP
include 'http://www.example.com/file.txt?foo=1&bar=2';

// Won't work; looks for a file named 'file.php?foo=1&bar=2' on the
// local filesystem.
include 'file.php?foo=1&bar=2';

// Works.
include 'http://www.example.com/file.php?foo=1&bar=2';

   

[!WARNING] A remote file may be processed at the remote server (depending on the file extension and whether or not the remote server runs PHP) but it still has to produce a valid PHP script because it will be processed at the local server. If the file from the remote server should be processed there and outputted only, readfile is a much better function to use. Otherwise, special care should be taken to secure the remote script to produce a valid and desired code.

See also Remote files, fopen and file for related information.

Handling Returns: include returns ENTITY on failure and raises a warning. Successful includes, unless overridden by the included file, return 1. It is possible to execute a return statement inside an included file in order to terminate processing in that file and return to the script which called it. Also, it's possible to return values from included files. You can take the value of the include call as you would for a normal function. This is not, however, possible when including remote files unless the output of the remote file has valid PHP start and end tags (as with any local file). You can declare the needed variables within those tags and they will be introduced at whichever point the file was included.

Because include is a special language construct, parentheses are not needed around its argument. Take care when comparing the return value.

Comparing return value of include

<?php
// won't work, evaluated as include(('vars.php') == TRUE), i.e. include('1')
if (include('vars.php') == TRUE) {
    echo 'OK';
}

// works
if ((include 'vars.php') == TRUE) {
    echo 'OK';
}

   

include and the return statement

return.php
<?php

$var = 'PHP';

return $var;

?>

noreturn.php
<?php

$var = 'PHP';

?>

testreturns.php
<?php

$foo = include 'return.php';

echo $foo; // prints 'PHP'

$bar = include 'noreturn.php';

echo $bar; // prints 1

?>

   

$bar is the value 1 because the include was successful. Notice the difference between the above examples. The first uses return within the included file while the other does not. If the file can't be included, ENTITY is returned and E_WARNING is issued.

If there are functions defined in the included file, they can be used in the main file regardless of whether they are before return or after. If the file is included twice, PHP will raise a fatal error because the functions were already declared. It is recommended to use include_once instead of checking if the file was already included and conditionally returning inside the included file.

Another way to "include" a PHP file into a variable is to capture the output by using the Output Control Functions with include. For example:

Using output buffering to include a PHP file into a string

<?php
$string = get_include_contents('somefile.php');

function get_include_contents($filename) {
    if (is_file($filename)) {
        ob_start();
        include $filename;
        return ob_get_clean();
    }
    return false;
}

   

In order to automatically include files within scripts, see also the auto_prepend_file and auto_append_file configuration options in ENTITY.

ENTITY

See also require, require_once, include_once, get_included_files, readfile, virtual, and include_path.

match

The match expression branches evaluation based on an identity check of a value. Similarly to a switch statement, a match expression has a subject expression that is compared against multiple alternatives. Unlike switch, it will evaluate to a value much like ternary expressions. Unlike switch, the comparison is an identity check (===) rather than a weak equality check (==). Match expressions are available as of PHP 8.0.0.

Structure of a match expression

<?php
$return_value = match (subject_expression) {
    single_conditional_expression => return_expression,
    conditional_expression1, conditional_expression2 => return_expression,
};

  

Basic match usage

<?php
$food = 'cake';

$return_value = match ($food) {
    'apple' => 'This food is an apple',
    'bar' => 'This food is a bar',
    'cake' => 'This food is a cake',
};

var_dump($return_value);

  

ENTITY

string(19) "This food is a cake"

Example of using match with comparison operators

<?php
$age = 18;

$output = match (true) {
    $age < 2 => "Baby",
    $age < 13 => "Child",
    $age <= 19 => "Teenager",
    $age >= 40 => "Adult",
    $age > 19 => "Young adult",
};

var_dump($output);

  

ENTITY

string(8) "Teenager"

[!NOTE] The result of a match expression does not need to be used.

[!NOTE] When a match expression is used as a standalone expression, it must be terminated by a semicolon ;.

The match expression is similar to a switch statement but has some key differences:

Like switch statements, match expressions are executed match arm by match arm. In the beginning, no code is executed. The conditional expressions are only evaluated if all previous conditional expressions failed to match the subject expression. Only the return expression corresponding to the matching conditional expression will be evaluated. For example:

<?php
$result = match ($x) {
    foo() => 'value',
    $this->bar() => 'value', // $this->bar() isn't called if foo() === $x
    $this->baz => beep(), // beep() isn't called unless $x === $this->baz
    // etc.
};

   

match expression arms may contain multiple expressions separated by a comma. That is a logical OR, and is a shorthand for multiple match arms with the same right-hand side.

<?php
$result = match ($x) {
    // This match arm:
    $a, $b, $c => 5,
    // Is equivalent to these three match arms:
    $a => 5,
    $b => 5,
    $c => 5,
};

   

A special case is the default pattern. This pattern matches anything that wasn't previously matched. For example:

<?php
$expressionResult = match ($condition) {
    1, 2 => foo(),
    3, 4 => bar(),
    default => baz(),
};

   

[!NOTE] Multiple default patterns will raise an E_FATAL_ERROR error.

A match expression must be exhaustive. If the subject expression is not handled by any match arm, an UnhandledMatchError is thrown.

Example of an unhandled match expression

<?php
$condition = 5;

try {
    match ($condition) {
        1, 2 => foo(),
        3, 4 => bar(),
    };
} catch (UnhandledMatchError $e) {
    var_dump($e);
}

  

ENTITY

object(UnhandledMatchError)#1 (7) {
  ["message":protected]=>
  string(22) "Unhandled match case 5"
  ["string":"Error":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(6) "script"
  ["line":protected]=>
  int(5)
  ["trace":"Error":private]=>
  array(0) {
  }
  ["previous":"Error":private]=>
  NULL
}

Using match expressions to handle non-identity checks

It is possible to use a match expression to handle non-identity conditional cases by using true as the subject expression.

Using a generalized match expression to branch on integer ranges

<?php
$age = 23;

$result = match (true) {
    $age >= 65 => 'senior',
    $age >= 25 => 'adult',
    $age >= 18 => 'young adult',
    default => 'kid',
};

var_dump($result);

   

ENTITY

string(11) "young adult"

Using a generalized match expression to branch on string content

<?php

$text = 'Bienvenue chez nous';

$result = match (true) {
    str_contains($text, 'Welcome'), str_contains($text, 'Hello') => 'en',
    str_contains($text, 'Bienvenue'), str_contains($text, 'Bonjour') => 'fr',
    // ...
};

var_dump($result);

   

ENTITY

string(2) "fr"

require_once

The require_once expression is identical to require except PHP will check if the file has already been included, and if so, not include (require) it again.

See the include_once documentation for information about the _once behaviour, and how it differs from its non _once siblings.

require

require is identical to include except upon failure it will also produce an Error exception (E_COMPILE_ERROR level error prior to PHP 8.0.0) whereas include will only produce a warning (E_WARNING level error).

See the include documentation for how this works.

return

return returns program control to the calling module. Execution resumes at the expression following the called module's invocation.

If called from within a function, the return statement immediately ends execution of the current function, and returns its argument as the value of the function call. return also ends the execution of an eval statement or script file.

If called from the global scope, then execution of the current script file is ended. If the current script file was included or required, then control is passed back to the calling file. Furthermore, if the current script file was included, then the value given to return will be returned as the value of the include call. If return is called from within the main script file, then script execution ends. If the current script file was named by the auto_prepend_file or auto_append_file configuration options in ENTITY, then that script file's execution is ended.

For more information, see Returning values.

[!NOTE] Note that since return is a language construct and not a function, the parentheses surrounding its argument are not required and their use is discouraged.

[!NOTE] If no parameter is supplied, then the parentheses must be omitted and ENTITY will be returned. Calling return with parentheses but with no arguments will result in a parse error.

As of PHP 7.1.0, return statements without an argument in functions which declare a return type trigger E_COMPILE_ERROR, unless the return type is void, in which case return statements with an argument trigger that error.

switch

The switch statement is similar to a series of if statements on the same expression. In situations where it is necessary to compare the same variable or expression with many different values, and execute a different piece of code depending on which value it equals, the switch statement is often more convenient and easier to read.

[!NOTE] Note that unlike some other languages, the continue statement applies to switch and acts similarly to break. If you have a switch inside a loop and wish to continue to the next iteration of the outer loop, use continue 2.

[!NOTE] Note that switch/case does a loose comparison.

In the following example, each code block is equivalent. One uses a series of if and elseif statements, and the other a switch statement. In each case, the output is the same.

switch structure

<?php
$i = 1;

// This switch statement:

switch ($i) {
    case 0:
        echo "i equals 0\n";
        break;
    case 1:
        echo "i equals 1\n";
        break;
    case 2:
        echo "i equals 2\n";
        break;
}

// Is equivalent to:
if ($i == 0) {
    echo "i equals 0\n";
} elseif ($i == 1) {
    echo "i equals 1\n";
} elseif ($i == 2) {
    echo "i equals 2\n";
}

   

ENTITY

i equals 1
i equals 1

It is important to understand how the switch statement is executed in order to avoid mistakes. The switch statement executes line by line (actually, statement by statement). In the beginning, no code is executed. Only when a case statement is found whose expression evaluates to a value that matches the value of the switch expression does PHP begin to execute the statements. PHP continues to execute the statements until the end of the switch block, or the first time it sees a break statement. If you don't write a break statement at the end of a case's statement list, PHP will go on executing the statements of the following case. For example:

<?php
$i = 1;

switch ($i) {
    case 0:
        echo "i equals 0\n";
    case 1:
        echo "i equals 1\n";
    case 2:
        echo "i equals 2\n";
}

   

ENTITY

i equals 1
i equals 2

Here, if $i is equal to 0, PHP would execute all of the echo statements! If $i is equal to 1, PHP would execute the last two echo statements. You would get the expected behavior ('i equals 2' would be displayed) only if $i is equal to 2. Thus, it is important not to forget break statements (even though you may want to avoid supplying them on purpose under certain circumstances).

In a switch statement, the condition is evaluated only once and the result is compared to each case statement. In an elseif statement, the condition is evaluated again. If your condition is more complicated than a simple comparison and/or is in a tight loop, a switch may be faster.

The statement list for a case can also be empty, which simply passes control into the statement list for the next case.

<?php
$i = 1;

switch ($i) {
    case 0:
    case 1:
    case 2:
        echo "i is less than 3 but not negative";
        break;
    case 3:
        echo "i is 3";
}

   

ENTITY

i is less than 3 but not negative

A special case is the default case. This case matches anything that wasn't matched by the other cases. For example:

<?php
$i = 4;

switch ($i) {
    case 0:
        echo "i equals 0";
        break;
    case 1:
        echo "i equals 1";
        break;
    case 2:
        echo "i equals 2";
        break;
    default:
       echo "i is not equal to 0, 1 or 2";
}

   

ENTITY

i is not equal to 0, 1 or 2

[!NOTE] Multiple default cases will raise an E_COMPILE_ERROR error.

[!NOTE] Technically the default case may be listed in any order. It will only be used if no other case matches. However, by convention it is best to place it at the end as the last branch.

If no case branch matches, and there is no default branch, then no code will be executed, just as if no if statement was true.

A case value may be given as an expression. However, that expression will be evaluated on its own and then loosely compared with the switch value. That means it cannot be used for complex evaluations of the switch value. For example:

<?php
$target = 1;
$start = 3;

switch ($target) {
    case $start - 1:
        print "A";
        break;
    case $start - 2:
        print "B";
        break;
    case $start - 3:
        print "C";
        break;
    case $start - 4:
        print "D";
        break;
}

   

ENTITY

B

For more complex comparisons, the value ENTITY may be used as the switch value. Or, alternatively, if-else blocks can be used instead of switch.

<?php
$offset = 1;
$start = 3;

switch (true) {
    case $start - $offset === 1:
        print "A";
        break;
    case $start - $offset === 2:
        print "B";
        break;
    case $start - $offset === 3:
        print "C";
        break;
    case $start - $offset === 4:
        print "D";
        break;
}

   

ENTITY

B

The alternative syntax for control structures is supported with switches. For more information, see Alternative syntax for control structures.

<?php
$i = 1;

switch ($i):
    case 0:
        echo "i equals 0";
        break;
    case 1:
        echo "i equals 1";
        break;
    case 2:
        echo "i equals 2";
        break;
    default:
        echo "i is not equal to 0, 1 or 2";
endswitch;

   

ENTITY

i equals 1

It's possible to use a semicolon instead of a colon after a case. As of PHP 8.5.0, this syntax is deprecated.

<?php
$beer = 'cola';

switch($beer)
{
    case 'tuborg';
    case 'carlsberg';
    case 'stella';
    case 'heineken';
        echo 'Good choice';
        break;
    default;
        echo 'Please make a new selection...';
        break;
}

   

ENTITY

Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in script on line 6

Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in script on line 7

Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in script on line 8

Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in script on line 9

Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in script on line 12
Please make a new selection...

ENTITY

ENTITY

ENTITY ENTITY
8.5.0 The alternate syntax using a semicolon after case has been deprecated.

ENTITY

ENTITY

throw

The ENTITY keyword is an expression and may be used in any expression context. It takes a Throwable object as an argument.

[!CAUTION] Prior to PHP 8.0.0, the ENTITY keyword was a statement and not an expression.

Attempting to ENTITY a non-Throwable object will throw an Error. As user classes cannot implement Throwable directly, the thrown object must be an instance of Error or Exception, or of a subclass of one of them.

Throwing a non-Throwable object

<?php
throw new class {};

   

ENTITY

PHP Fatal error:  Uncaught Error: Cannot throw objects that do not implement Throwable in Command line code:1
Stack trace:
#0 {main}

After using ENTITY, the normal flow of execution is halted and the call stack is unwound until the object is caught by a ENTITY block or the global scope is reached. All ENTITY blocks encountered along the way are executed. If the global scope is reached, the object is passed to the exception handler set with set_exception_handler, if one is set, and the script terminates once the handler returns. Otherwise, the program is terminated with a fatal error containing the stack trace indicating where the Throwable object was thrown.

Throwing an Exception in the global scope

<?php
echo "Before exception\n";
throw new Exception('Stop execution');
echo "After exception\n";

  

ENTITY

Before exception
PHP Fatal error:  Uncaught Exception: Stop execution in Command line code:2
Stack trace:
#0 {main}
  thrown in Command line code on line 2

Throwing an Exception in a function

   
<?php

function foo() {
    echo "Before exception\n";
    throw new Exception('Stop execution');
    echo "After exception\n";
}

foo();

  

ENTITY

Before exception
PHP Fatal error:  Uncaught Exception: Stop execution in Command line code:3
Stack trace:
#0 Command line code(7): foo()
#1 {main}
  thrown in Command line code on line 3

As ENTITY is an expression, it can be used to branch out on the result of another expression if its value is inappropriate.

Using throw as an expression

Only permitted as of PHP 8.0.0.

<?php

function test() {
    do_something_risky() or throw new Exception('It did not work');
}

function do_something_risky() {
    return false; // Simulate failure
}

try {
    test();
} catch (Exception $e) {
    print $e->getMessage();
}

  

ENTITY

It did not work

It is possible to handle a thrown Throwable by using a try-catch block. See the error handling section for more information.

try...catch

try

A ENTITY block delimits a segment of code which might ENTITY a Throwable error that needs handling. A ENTITY block must have at least one corresponding ENTITY or ENTITY block.

When a Throwable error is thrown in a ENTITY block, PHP will attempt to find the first matching ENTITY block to handle the error. If none can be found, the call stack is unwound until a matching ENTITY block is found or the global scope is reached. An uncaught object is then passed to the exception handler set with set_exception_handler, if one is set; otherwise, the script terminates with a fatal error.

catch

A ENTITY block defines how to respond to a thrown Throwable error. It specifies one or more subclasses of Throwable (most commonly Exception) it can handle, and optionally a variable to which the exception is assigned.

The first ENTITY block that matches the class of the thrown Throwable object will handle the error. Normal execution resumes after the ENTITY block without entering any other matching ENTITY blocks.

[!NOTE] It is not recommended to catch Error objects, as they signal a programming error.

Catching an Exception

<?php
try {
    throw new Exception('Error');
} catch (Exception $e) {
    echo 'Caught exception: ', $e->getMessage(), "\n";
}

// Continue execution
echo "Hello World\n";

   

ENTITY

Caught exception: Error
Hello World

As of PHP 7.1.0, a ENTITY block may specify a union of Throwable subclasses that the block should handle using the pipe (|) character. This is useful when different exceptions from different class hierarchies are handled in the same way.

Catching a union of classes to handle

<?php

class MyException extends Exception { }

class MyOtherException extends Exception { }

class Test {
    public function testing() {
        try {
            throw new MyException();
        } catch (MyException | MyOtherException $e) {
            var_dump(get_class($e));
        }
    }
}

$foo = new Test;
$foo->testing();

   

ENTITY

string(11) "MyException"

Multiple ENTITY blocks can be used to handle different classes of Throwable errors in different ways.

Multiple catch blocks

<?php
try {
    do_something_io_related();
} catch (FileNotFoundException $e) {
    // Only catch FileNotFoundException and do something in this case
} catch (MissingPermissionException $e) {
    // Only catch MissingPermissionException and do something different in this case
}

   

Throwables can be ENTITYn (or re-thrown) within a ENTITY block.

Nested Exception

<?php

class MyException extends Exception { }

class Test {
    public function testing() {
        try {
            try {
                throw new MyException('foo!');
            } catch (MyException $e) {
                // rethrow it
                throw $e;
            }
        } catch (Exception $e) {
            var_dump($e->getMessage());
        }
    }
}

$foo = new Test;
$foo->testing();

   

ENTITY

string(4) "foo!"

[!CAUTION] An object thrown inside a ENTITY block will not be caught by an adjacent ENTITY block.

Sequential catch blocks

<?php

class A extends Exception {}
class B extends Exception {}

try {
    throw new A;
} catch (A $e) {
    throw new B;
} catch (B) {
    echo 'Hello';
}


    

ENTITY

Fatal error: Uncaught B in /in/K8Tl9:9
Stack trace:
#0 {main}
  thrown in /in/K8Tl9 on line 9

As of PHP 8.0.0, the variable name for a caught Throwable is optional. If not specified, the ENTITY block will still execute but will not have access to the thrown object.

Omitting the caught variable

Only permitted as of PHP 8.0.0.

<?php

class SpecificException extends Exception {}

function test() {
    throw new SpecificException('Oopsie');
}

try {
    test();
} catch (SpecificException) {
    print "A SpecificException was thrown, but we don't care about the details.";
}

   

ENTITY

A SpecificException was thrown, but we don't care about the details.

See the error handling section for the Throwable hierarchy and how to define custom exceptions.

while

while loops are the simplest type of loop in PHP. They behave just like their C counterparts. The basic form of a while statement is:

while (expr)
    statement

The meaning of a while statement is simple. It tells PHP to execute the nested statement(s) repeatedly, as long as the while expression evaluates to ENTITY. The value of the expression is checked each time at the beginning of the loop, so even if this value changes during the execution of the nested statement(s), execution will not stop until the end of the iteration (each time PHP runs the statements in the loop is one iteration). If the while expression evaluates to ENTITY from the very beginning, the nested statement(s) won't even be run once.

Like with the if statement, you can group multiple statements within the same while loop by surrounding a group of statements with curly braces, or by using the alternate syntax:

while (expr):
    statement
    ...
endwhile;

The following examples are identical, and both print the numbers 1 through 10:

<?php
$i = 1;
while ($i <= 10) {
    echo $i++ . "\n";  /* the printed value would be
                          $i before the increment
                          (post-increment) */
}

   

ENTITY

1
2
3
4
5
6
7
8
9
10
<?php
$i = 1;
while ($i <= 10):
    echo $i . "\n";
    $i++;
endwhile;

   

ENTITY

1
2
3
4
5
6
7
8
9
10

Enumerations

Enumerations overview

Enumerations, or "Enums", allow a developer to define a custom type that is limited to one of a discrete number of possible values. That can be especially helpful when defining a domain model, as it enables "making invalid states unrepresentable."

Enums appear in many languages with a variety of different features. In PHP, Enums are a special kind of object. The Enum itself is a class, and its possible cases are all single-instance objects of that class. That means Enum cases are valid objects and may be used anywhere an object may be used, including type checks.

Basic enumerations

Enums are similar to classes, and share the same namespaces as classes, interfaces, and traits. They are also autoloadable the same way. An Enum defines a new type, which has a fixed, limited number of possible legal values.

<?php

enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

   

This declaration creates a new enumerated type named Suit, which has four and only four legal values: Suit::Hearts, Suit::Diamonds, Suit::Clubs, and Suit::Spades. Variables may be assigned to one of those legal values. A function may be type checked against an enumerated type, in which case only values of that type may be passed.

<?php

enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

function pick_a_card(Suit $suit)
{
    var_dump($suit);
}

$val = Suit::Diamonds;

// OK
pick_a_card($val);

// OK
pick_a_card(Suit::Clubs);

// TypeError: pick_a_card(): Argument #1 ($suit) must be of type Suit, string given
pick_a_card('Spades');

    

An Enumeration may have zero or more case definitions, with no maximum. A zero-case enum is syntactically valid, if rather useless.

For Enumeration cases, the same syntax rules apply as to any label in PHP, see Constants.

By default, cases are not intrinsically backed by a scalar value. That is, Suit::Hearts is not equal to "0". Instead, each case is backed by a singleton object of that name. That means that:

<?php

enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

$a = Suit::Spades;
$b = Suit::Spades;

if ($a === $b) {
    print "Suits match using ===\n";
}

if ($a instanceof Suit) {
    print "Suits match using instanceof\n";
}

if ($a !== 'Spades') {
    print "Suit does not match the string\n";
}

    

It also means that enum values are never ENTITY or ENTITY each other, since those comparisons are not meaningful on objects. Those comparisons will always return ENTITY when working with enum values.

This type of case, with no related data, is called a "Pure Case." An Enum that contains only Pure Cases is called a Pure Enum.

All Pure Cases are implemented as instances of their enum type. The enum type is represented internally as a class.

All Cases have a read-only property, name, that is the case-sensitive name of the case itself.

<?php

enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

print Suit::Spades->name;
// prints "Spades"

    

It is also possible to use the defined and constant functions to check for the existence of or read an enum case if the name is obtained dynamically. This is, however, discouraged as using Backed enums should work for most use cases.

Backed enumerations

By default, Enumerated Cases have no scalar equivalent. They are simply singleton objects. However, there are ample cases where an Enumerated Case needs to be able to round-trip to a database or similar datastore, so having a built-in scalar (and thus trivially serializable) equivalent defined intrinsically is useful.

To define a scalar equivalent for an Enumeration, the syntax is as follows:

<?php

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

  

A case that has a scalar equivalent is called a Backed Case, as it is "Backed" by a simpler value. An Enum that contains all Backed Cases is called a "Backed Enum." A Backed Enum may contain only Backed Cases. A Pure Enum may contain only Pure Cases.

A Backed Enum may be backed by types of int or string, and a given enumeration supports only a single type at a time (that is, no union of int|string). If an enumeration is marked as having a scalar equivalent, then all cases must have a unique scalar equivalent defined explicitly. There are no auto-generated scalar equivalents (e.g., sequential integers). Backed cases must be unique; two backed enum cases may not have the same scalar equivalent. However, a constant may refer to a case, effectively creating an alias. See Enumeration constants.

The equivalent values may be a constant scalar expression. Prior to PHP 8.2.0, the equivalent values had to be literals or literal expressions. This means that constants and constant expressions were not supported. That is, 1 + 1 was allowed, but 1 + SOME_CONST was not.

Backed Cases have an additional read-only property, value, which is the value specified in the definition.

<?php

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

print Suit::Clubs->value;
// Prints "C"

   

In order to enforce the value property as read-only, a variable cannot be assigned as a reference to it. That is, the following throws an error:

<?php

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

$suit = Suit::Clubs;
$ref = &$suit->value;
// Fatal Error: Cannot indirectly modify readonly property Suit::$value

   

Backed enums implement an internal BackedEnum interface, which exposes two additional methods:

from(int|string): self

will take a scalar and return the corresponding Enum Case. If one is not found, it will throw a

ValueError

. This is mainly useful in cases where the input scalar is trusted and a missing enum value should be considered an application-stopping error.

tryFrom(int|string): ?self

will take a scalar and return the corresponding Enum Case. If one is not found, it will return ENTITY. This is mainly useful in cases where the input scalar is untrusted and the caller wants to implement their own error handling or default-value logic.

The from() and tryFrom() methods follow standard weak/strong typing rules. In weak typing mode, passing an integer or string is acceptable and the system will coerce the value accordingly. Passing a float will also work and be coerced. In strict typing mode, passing an integer to from() on a string-backed enum (or vice versa) will result in a TypeError, as will a float in all circumstances. All other parameter types will throw a TypeError in both modes.

<?php

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

function get_stuff_from_database($id) {
    return [
        'suit' => 'S',
    ];
}

$record = get_stuff_from_database(42);
print $record['suit'] . "\n";

$suit = Suit::tryFrom('A') ?? Suit::Spades;
// Invalid data returns null, so Suit::Spades is used instead.
print $suit->value . "\n";

$suit =  Suit::from('X');
// Invalid data throws a ValueError: "X" is not a valid backing scalar value for enum Suit
print $suit->value . "\n";

   

Manually defining a from() or tryFrom() method on a Backed Enum will result in a fatal error.

Enumeration methods

Enums (both Pure Enums and Backed Enums) may contain methods, and may implement interfaces. If an Enum implements an interface, then any type check for that interface will also accept all cases of that Enum.

<?php

interface Colorful
{
    public function color(): string;
}

enum Suit implements Colorful
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;

    // Fulfills the interface contract.
    public function color(): string
    {
        return match ($this) {
            Suit::Hearts, Suit::Diamonds => 'Red',
            Suit::Clubs, Suit::Spades => 'Black',
        };
    }

    // Not part of an interface; that's fine.
    public function shape(): string
    {
        return "Rectangle";
    }
}

function paint(Colorful $c)
{
   print $c->color() . "\n";
}

paint(Suit::Clubs);  // Works

print Suit::Diamonds->shape(); // prints "Rectangle"

   

In this example, all four instances of Suit have two methods, color() and shape(). As far as calling code and type checks are concerned, they behave exactly the same as any other object instance.

On a Backed Enum, the interface declaration goes after the backing type declaration.

   
<?php

interface Colorful
{
    public function color(): string;
}

enum Suit: string implements Colorful
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';

    // Fulfills the interface contract.
    public function color(): string
    {
        return match ($this) {
            Suit::Hearts, Suit::Diamonds => 'Red',
            Suit::Clubs, Suit::Spades => 'Black',
        };
    }
}

  

Inside a method, the $this variable is defined and refers to the Case instance.

Methods may be arbitrarily complex, but in practice will usually return a static value or ENTITY on $this to provide different results for different cases.

Note that in this case it would be a better data modeling practice to also define a SuitColor Enum Type with values Red and Black and return that instead. However, that would complicate this example.

The above hierarchy is logically similar to the following class structure (although this is not the actual code that runs):

<?php

interface Colorful
{
    public function color(): string;
}

final class Suit implements UnitEnum, Colorful
{
    public const Hearts = new self('Hearts');
    public const Diamonds = new self('Diamonds');
    public const Clubs = new self('Clubs');
    public const Spades = new self('Spades');

    private function __construct(public readonly string $name) {}

    public function color(): string
    {
        return match ($this) {
            Suit::Hearts, Suit::Diamonds => 'Red',
            Suit::Clubs, Suit::Spades => 'Black',
        };
    }

    public function shape(): string
    {
        return "Rectangle";
    }

    public static function cases(): array
    {
        // Illegal method, because manually defining a cases() method on an Enum is disallowed.
        // See also "Value listing" section.
    }
}

  

Methods may be public, private, or protected, although in practice private and protected are equivalent as inheritance is not allowed.

Enumeration static methods

Enumerations may also have static methods. The use for static methods on the enumeration itself is primarily for alternative constructors. E.g.:

<?php

enum Size
{
    case Small;
    case Medium;
    case Large;

    public static function fromLength(int $cm): self
    {
        return match (true) {
            $cm < 50 => self::Small,
            $cm < 100 => self::Medium,
            default => self::Large,
        };
    }
}

var_dump(Size::fromLength(50));

   

Static methods may be public, private, or protected, although in practice private and protected are equivalent as inheritance is not allowed.

Enumeration constants

Enumerations may include constants, which may be public, private, or protected, although in practice private and protected are equivalent as inheritance is not allowed.

An enum constant may refer to an enum case:

<?php

enum Size
{
    case Small;
    case Medium;
    case Large;

    public const Huge = self::Large;
}

var_dump(Size::Huge);

   

Traits

Enumerations may leverage traits, which will behave the same as on classes. The caveat is that traits used in an enum must not contain properties. They may only include methods, static methods, and constants. A trait with properties will result in a fatal error.

<?php

interface Colorful
{
    public function color(): string;
}

trait Rectangle
{
    public function shape(): string
    {
        return "Rectangle";
    }
}

enum Suit implements Colorful
{
    use Rectangle;

    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;

    public function color(): string
    {
        return match ($this) {
            Suit::Hearts, Suit::Diamonds => 'Red',
            Suit::Clubs, Suit::Spades => 'Black',
        };
    }
}

$suit = Suit::Spades;
var_dump($suit->color());
var_dump($suit->shape());

   

Enum values in constant expressions

Because cases are represented as constants on the enum itself, they may be used as static values in most constant expressions: property defaults, static variable defaults, parameter defaults, global and class constant values. They may not be used in other enum case values, but normal constants may refer to an enum case.

However, implicit magic method calls such as ArrayAccess on enums are not allowed in static or constant definitions as we cannot absolutely guarantee that the resulting value is deterministic or that the method invocation is free of side effects. Function calls, method calls, and property access continue to be invalid operations in constant expressions.

<?php

// This is an entirely legal Enum definition.
enum Direction implements ArrayAccess
{
    case Up;
    case Down;

    public function offsetExists($offset): bool
    {
        return false;
    }

    public function offsetGet($offset): mixed
    {
        return null;
    }

    public function offsetSet($offset, $value): void
    {
        throw new Exception();
    }

    public function offsetUnset($offset): void
    {
        throw new Exception();
    }
}

class Foo
{
    // This is allowed.
    const DOWN = Direction::Down;

    // This is disallowed, as it may not be deterministic.
    const UP = Direction::Up['short'];
    // Fatal error: Cannot use [] on enums in constant expression
}

// This is entirely legal, because it's not a constant expression.
$x = Direction::Up['short'];
var_dump("\$x is " . var_export($x, true));

$foo = new Foo();

  

Differences from objects

Although Enums are built on classes and objects, they do not support all object-related functionality. In particular, Enum cases are forbidden from having state.

Constructors and Destructors are forbidden.

Inheritance is not supported. Enums may not extend or be extended.

Static or object properties are not allowed.

Cloning an Enum case is not supported, as cases must be singleton instances.

Magic methods

, except for those listed below, are disallowed.

Enums must always be declared before they are used.

The following object functionality is available, and behaves just as it does on any other object:

Public, private, and protected methods.

Public, private, and protected static methods.

Public, private, and protected constants.

Enums may implement any number of interfaces.

Enums and cases may have

attributes

attached to them. The

TARGET_CLASS

target filter includes Enums themselves. The

TARGET_CLASS_CONST

target filter includes Enum Cases.

__call

,

__callStatic

, and

__invoke

magic methods

__CLASS__

and

__FUNCTION__

constants behave as normal

The ::class magic constant on an Enum type evaluates to the type name including any namespace, exactly the same as an object. The ::class magic constant on a Case instance also evaluates to the Enum type, as it is an instance of that type.

Additionally, enum cases may not be instantiated directly with new, nor with ReflectionClass::newInstanceWithoutConstructor in reflection. Both will result in an error.

<?php

$clovers = new Suit();
// Error: Cannot instantiate enum Suit

$horseshoes = (new ReflectionClass(Suit::class))->newInstanceWithoutConstructor()
// Error: Cannot instantiate enum Suit

  

Value listing

Both Pure Enums and Backed Enums implement an internal interface named UnitEnum. UnitEnum includes a static method cases(). cases() returns a packed array of all defined Cases in the order of declaration.

<?php

enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

var_dump(Suit::cases());

enum SuitBacked: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

var_dump(SuitBacked::cases());

   

Manually defining a cases() method on an Enum will result in a fatal error.

Serialization

Enumerations are serialized differently from objects. Specifically, they have a new serialization code, "E", that specifies the name of the enum case. The deserialization routine is then able to use that to set a variable to the existing singleton value. That ensures that:

<?php

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

Suit::Hearts === unserialize(serialize(Suit::Hearts));

print serialize(Suit::Hearts);
// E:11:"Suit:Hearts";

   

On deserialization, if an enum and case cannot be found to match a serialized value a warning will be issued and ENTITY returned.

The allowed_classes option of unserialize does not affect Enumerations.

If a Pure Enum is serialized to JSON, an error will be thrown. If a Backed Enum is serialized to JSON, it will be represented by its scalar value only, in the appropriate type. The behavior of both may be overridden by implementing JsonSerializable.

For print_r, the output of an enum case is slightly different from objects to minimize confusion.

<?php

enum Foo
{
    case Bar;
}

enum Baz: int
{
    case Beep = 5;
}

print_r(Foo::Bar);
print_r(Baz::Beep);

/* Produces

Foo Enum (
    [name] => Bar
)
Baz Enum:int {
    [name] => Beep
    [value] => 5
}
*/

   

Why enums aren't extendable

Classes have contracts on their methods:

<?php

class A {}
class B extends A {}

function foo(A $a) {}

function bar(B $b)
{
    foo($b);
}

 

This code is type-safe, as B follows the contract of A, and through the magic of co/contra-variance, any expectation one may have of the methods will be preserved, exceptions excepted.

Enums have contracts on their cases, not methods:

<?php

enum ErrorCode
{
    case SOMETHING_BROKE;
}

function quux(ErrorCode $errorCode)
{
    // When written, this code appears to cover all cases
    match ($errorCode) {
        ErrorCode::SOMETHING_BROKE => true,
    };
}

  

The ENTITY statement in the function quux can be static analyzed to cover all of the cases in ErrorCode.

But imagine it was allowed to extend enums:

<?php

// Thought experiment code where enums are not final.
// Note, this won't actually work in PHP.
enum MoreErrorCode extends ErrorCode
{
    case PEBKAC;
}

function fot(MoreErrorCode $errorCode)
{
    quux($errorCode);
}

fot(MoreErrorCode::PEBKAC);

  

Under normal inheritance rules, a class that extends another will pass the type check.

The problem would be that the ENTITY statement in quux() no longer covers all the cases. Because it doesn't know about MoreErrorCode::PEBKAC the match will throw an exception.

Because of this enums are final and can't be extended.

ENTITY

Basic limited values

<?php

enum SortOrder
{
    case Asc;
    case Desc;
}

function query($fields, $filter, SortOrder $order = SortOrder::Asc)
{
     /* ... */
}

    

The query() function can now proceed safe in the knowledge that $order is guaranteed to be either SortOrder::Asc or SortOrder::Desc. Any other value would have resulted in a TypeError, so no further error checking or testing is needed.

Advanced exclusive values

<?php

enum UserStatus: string
{
    case Pending = 'P';
    case Active = 'A';
    case Suspended = 'S';
    case CanceledByUser = 'C';

    public function label(): string
    {
        return match ($this) {
            self::Pending => 'Pending',
            self::Active => 'Active',
            self::Suspended => 'Suspended',
            self::CanceledByUser => 'Canceled by user',
        };
    }
}

$status = UserStatus::Suspended;
var_dump($status->label());

    

In this example, a user's status may be one of, and exclusively, UserStatus::Pending, UserStatus::Active, UserStatus::Suspended, or UserStatus::CanceledByUser. A function can type a parameter against UserStatus and then only accept those four values, period.

All four values have a label() method, which returns a human-readable string. That string is independent of the "machine name" scalar equivalent string, which can be used in, for example, a database field or an HTML select box.

<?php

enum UserStatus: string
{
    case Pending = 'P';
    case Active = 'A';
    case Suspended = 'S';
    case CanceledByUser = 'C';

    public function label(): string
    {
        return match($this) {
            self::Pending => 'Pending',
            self::Active => 'Active',
            self::Suspended => 'Suspended',
            self::CanceledByUser => 'Canceled by user',
        };
    }
}

foreach (UserStatus::cases() as $case) {
    printf(
        "<option value=\"%s\">%s</option>\n",
        htmlentities($case->value),
        htmlentities($case->label())
    );
}

    

Error Handling

Errors are a normal part of the development and life cycle of an application. As such, PHP provides multiple ways to report and deal with errors.

PHP has two main mechanisms for reporting errors:

Throwable errors

A Throwable error is an execution event which disrupts the normal flow of instructions. When a Throwable error is ENTITYn, it will unwind the call stack until it is caught by a ENTITY block or the global scope is reached. All ENTITY blocks it encounters along the way will be executed. An uncaught Throwable error is passed to the exception handler set with set_exception_handler, if one is set; otherwise, the program is terminated with a fatal error.

To throw a Throwable error from within PHP code, use the ENTITY keyword.

[!TIP] The Standard PHP Library (SPL) provides various built-in exceptions. It is also possible to create custom exceptions by extending the Exception class.

It is possible to handle a Throwable error within PHP by surrounding the code that may throw an error in a ENTITY block.

[!WARNING] Throwable objects cannot be cloned. Attempting to clone such an object throws an Error with the following message: Trying to clone an uncloneable object of class ClassName. This happens even if a subclass declares its own __clone() method. See Exception::__clone and Error::__clone.

Global exception handler

It's possible to add a handler for any uncaught Throwable with set_exception_handler. This is similar to wrapping the entire code in a ENTITY-ENTITY block, except that execution does not resume afterwards: the script terminates once the handler returns.

Extending exceptions

A user-defined exception can be defined by extending the built-in Exception class.

If a class extends the built-in Exception class and redefines the constructor, it is highly recommended that it also call parent::__construct() to ensure all available data has been properly assigned. The __toString() method can be overridden to provide custom output when the object is used as a string.

Extending Exception

<?php
class CustomException extends Exception
{
    // Redefine the constructor so message isn't optional
    public function __construct($message, $code = 0, ?Throwable $previous = null) {
        // some code

        // Ensure everything is assigned properly
        parent::__construct($message, $code, $previous);
    }

    // Custom string representation of object
    public function __toString() {
        return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
    }

    public function customFunction() {
        echo "A custom function for this type of exception\n";
    }
}

try {
    throw new CustomException("Something happened", 5);
} catch (CustomException $e) {
    echo "Caught custom exception\n", $e;
    $e->customFunction();
}

    

ENTITY

Caught custom exception
CustomException: [5]: Something happened
A custom function for this type of exception

Throwable hierarchy

The Exception class has many subclasses, among them the SPL exceptions and those defined by extensions.

Diagnostic errors

Diagnostic errors, also known as traditional errors, are used to signal a number of different conditions, and can be displayed and/or logged as required. By default, PHP will report all diagnostic errors. (Prior to PHP 8.0.0, E_NOTICE and E_DEPRECATED diagnostics were not reported by default.)

In contrast to Throwable errors, most diagnostic errors do not disrupt the normal flow of execution. Fatal diagnostics, such as E_ERROR, terminate the script.

Which diagnostics are reported and which are ignored is controlled by the error_reporting ENTITY directive, or at runtime by calling error_reporting. It is strongly recommended that the configuration directive be set, as some errors can occur before execution of your script begins.

[!NOTE] In a development environment, error_reporting should always be set to E_ALL so that issues raised by PHP are noticed and fixed. In production, the level of verbosity can be reduced to E_ALL ENTITY ~E_NOTICE ENTITY ~E_DEPRECATED, although in many cases E_ALL is still appropriate, as it may provide early warning of potential issues.

What happens to the diagnostics depends on two further ENTITY directives. display_errors controls whether the diagnostic is shown as part of the script's output. This should always be disabled in a production environment, as the output can include confidential information such as database passwords, but is often useful to enable in development, as it ensures immediate reporting of issues.

In addition to displaying errors, PHP can log diagnostics when the log_errors directive is enabled. This will log any diagnostic to the file or syslog defined by error_log. This can be extremely useful in a production environment, as diagnostics are logged when they occur, and reports can then be generated from those logs.

Individual diagnostics can be suppressed using the @ operator.

[!WARNING] Prior to PHP 8.0.0, it was possible to suppress critical diagnostics that would terminate the execution of the PHP script.

[!NOTE] Between PHP versions, diagnostics may be added or removed, have their severity changed, or be elevated to Throwable errors.

User-defined diagnostic handler

If PHP's default diagnostic handling is inadequate, it is possible to override the default diagnostic handler with a custom one which is set using set_error_handler. Some diagnostics, such as E_ERROR and E_PARSE, cannot be handled this way (see set_error_handler for the full list). The others can be handled in various ways. For example, a custom handler can show an error page to the user and report the error more directly than a log would, such as by sending an email.

Another typical usage is to elevate diagnostic errors to exceptions with ErrorException.

Elevating diagnostic errors to exceptions

<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
    if (error_reporting() & $severity) {
        throw new ErrorException($message, 0, $severity, $filename, $lineno);
    }
}

set_error_handler('exceptions_error_handler');

    

[!NOTE] It is important to verify that the severity is included in the current list of reportable diagnostics; otherwise, the @ operator will be broken, as an exception will be thrown for a suppressed diagnostic.

ENTITY

ENTITY ENTITY
8.5.0 Fatal errors (such as an exceeded maximum execution time) now include a stack trace in their error message.

Expressions

Expressions are the most important building blocks of PHP. In PHP, almost anything you write is an expression. The simplest yet most accurate way to define an expression is "anything that has a value".

The most basic forms of expressions are constants and variables. When you type $a = 5, you're assigning 5 into $a. 5, obviously, has the value 5, or in other words 5 is an expression with the value of 5 (in this case, 5 is an integer constant).

After this assignment, you'd expect $a's value to be 5 as well, so if you wrote $b = $a, you'd expect it to behave just as if you wrote $b = 5. In other words, $a is an expression with the value of 5 as well. If everything works right, this is exactly what will happen.

Slightly more complex examples for expressions are functions. For instance, consider the following function:

<?php
function foo ()
{
    return 5;
}
?>

     

Assuming you're familiar with the concept of functions (if you're not, take a look at the chapter about functions), you'd assume that typing $c = foo() is essentially just like writing $c = 5, and you're right. Functions are expressions with the value of their return value. Since foo() returns 5, the value of the expression 'foo()' is 5. Usually functions don't just return a static value but compute something.

Of course, values in PHP don't have to be integers, and very often they aren't. PHP supports four scalar value types: int values, floating point values (float), string values and bool values (scalar values are values that you can't 'break' into smaller pieces, unlike arrays, for instance). PHP also supports two composite (non-scalar) types: arrays and objects. Each of these value types can be assigned into variables or returned from functions.

PHP takes expressions much further, in the same way many other languages do. PHP is an expression-oriented language, in the sense that almost everything is an expression. Consider the example we've already dealt with, $a = 5. It's easy to see that there are two values involved here, the value of the integer constant 5, and the value of $a which is being updated to 5 as well. But the truth is that there's one additional value involved here, and that's the value of the assignment itself. The assignment itself evaluates to the assigned value, in this case 5. In practice, it means that $a = 5, regardless of what it does, is an expression with the value 5. Thus, writing something like $b = ($a = 5) is like writing $a = 5; $b = 5; (a semicolon marks the end of a statement). Since assignments are parsed in a right to left order, you can also write $b = $a = 5.

Another good example of expression orientation is pre- and post-increment and decrement. Users of PHP and many other languages may be familiar with the notation of variable++ and variable--. These are increment and decrement operators. In PHP, like in C, there are two types of increment - pre-increment and post-increment. Both pre-increment and post-increment essentially increment the variable, and the effect on the variable is identical. The difference is with the value of the increment expression. Pre-increment, which is written ++$variable, evaluates to the incremented value (PHP increments the variable before reading its value, thus the name 'pre-increment'). Post-increment, which is written $variable++ evaluates to the original value of $variable, before it was incremented (PHP increments the variable after reading its value, thus the name 'post-increment').

A very common type of expressions are comparison expressions. These expressions evaluate to either ENTITY or ENTITY. PHP supports ENTITY (bigger than), ENTITY= (bigger than or equal to), == (equal), != (not equal), ENTITY (smaller than) and ENTITY= (smaller than or equal to). The language also supports a set of strict equivalence operators: === (equal to and same type) and !== (not equal to or not same type). These expressions are most commonly used inside conditional execution, such as if statements.

The last example of expressions we'll deal with here is combined operator-assignment expressions. You already know that if you want to increment $a by 1, you can simply write $a++ or ++$a. But what if you want to add more than one to it, for instance 3? You could write $a++ multiple times, but this is obviously not a very efficient or comfortable way. A much more common practice is to write $a = $a + 3. $a + 3 evaluates to the value of $a plus 3, and is assigned back into $a, which results in incrementing $a by 3. In PHP, as in several other languages like C, you can write this in a shorter way, which with time would become clearer and quicker to understand as well. Adding 3 to the current value of $a can be written $a += 3. This means exactly "take the value of $a, add 3 to it, and assign it back into $a". In addition to being shorter and clearer, this also results in faster execution. The value of $a += 3, like the value of a regular assignment, is the assigned value. Notice that it is NOT 3, but the combined value of $a plus 3 (this is the value that's assigned into $a). Any two-place operator can be used in this operator-assignment mode, for example $a -= 5 (subtract 5 from the value of $a), $b *= 7 (multiply the value of $b by 7), etc.

There is one more expression that may seem odd if you haven't seen it in other languages, the ternary conditional operator:

<?php
$first ? $second : $third
?>

     

If the value of the first subexpression is ENTITY (non-zero), then the second subexpression is evaluated, and that is the result of the conditional expression. Otherwise, the third subexpression is evaluated, and that is the value.

The following example should help you understand pre- and post-increment and expressions in general a bit better:

<?php
function double($i)
{
    return $i * 2;
}

$b = $a = 5;        /* assign the value five into the variable $a and $b */
$c = $a++;          /* post-increment, assign original value of $a 
                       (5) to $c */
print "a = {$a}; b = {$b}; c = {$c}" . PHP_EOL;

$e = $d = ++$b;     /* pre-increment, assign the incremented value of 
                       $b (6) to $d and $e */
print "b = {$b}; d = {$d}; e = {$e}" . PHP_EOL;

/* at this point, both $d and $e are equal to 6 */

$f = double($d++);  /* assign twice the value of $d before
                       the increment, 2*6 = 12 to $f */
print "d = {$d}; f = {$f}" . PHP_EOL;

$g = double(++$e);  /* assign twice the value of $e after
                       the increment, 2*7 = 14 to $g */
print "e = {$e}; g = {$g}" . PHP_EOL;

$h = $g += 10;      /* first, $g is incremented by 10 and ends with the 
                       value of 24. the value of the assignment (24) is 
                       then assigned into $h, and $h ends with the value 
                       of 24 as well. */
print "g = {$g}; h = {$h}" . PHP_EOL;
?>

     

Some expressions can be considered as statements. In this case, a statement has the form of 'expr ;' that is, an expression followed by a semicolon. In $b = $a = 5;, $a = 5 is a valid expression, but it's not a statement by itself. $b = $a = 5;, however, is a valid statement.

One last thing worth mentioning is the truth value of expressions. In many events, mainly in conditional execution and loops, you're not interested in the specific value of the expression, but only care about whether it means ENTITY or ENTITY. The constants ENTITY and ENTITY (case-insensitive) are the two possible boolean values. When necessary, an expression is automatically converted to boolean. See the section about type-casting for details about how.

PHP provides a full and powerful implementation of expressions, and documenting it entirely goes beyond the scope of this manual. The above examples should give you a good idea about what expressions are and how you can construct useful expressions. Throughout the rest of this manual we'll write expr to indicate any valid PHP expression.

Fibers

Fibers overview

Fibers represent full-stack, interruptible functions. Fibers may be suspended from anywhere in the call-stack, pausing execution within the fiber until the fiber is resumed at a later time.

Fibers pause the entire execution stack, so the direct caller of the function does not need to change how it invokes the function.

Execution may be interrupted anywhere in the call stack using Fiber::suspend (that is, the call to Fiber::suspend may be in a deeply nested function or not even exist at all).

Unlike stack-less Generators, each Fiber has its own call stack, allowing them to be paused within deeply nested function calls. A function declaring an interruption point (that is, calling Fiber::suspend) need not change its return type, unlike a function using ENTITY which must return a Generator instance.

Fibers can be suspended in any function call, including those called from within the PHP VM, such as functions provided to array_map or methods called by ENTITY on an Iterator object.

Once suspended, execution of the fiber may be resumed with any value using Fiber::resume or by throwing an exception into the fiber using Fiber::throw. The value is returned (or exception thrown) from Fiber::suspend.

[!NOTE] Prior to PHP 8.4.0, switching fibers during the execution of an object destructor was not allowed.

Basic usage

    
<?php
$fiber = new Fiber(function (): void {
   $value = Fiber::suspend('fiber');
   echo "Value used to resume fiber: ", $value, PHP_EOL;
});

$value = $fiber->start();

echo "Value from fiber suspending: ", $value, PHP_EOL;

$fiber->resume('test');
?>

   

ENTITY

Value from fiber suspending: fiber
Value used to resume fiber: test

Functions

User-defined functions

A function is defined using the function keyword, a name, a list of parameters (which might be empty) separated by commas (,) enclosed in parentheses, followed by the body of the function enclosed in curly braces, such as the following:

Declaring a new function named foo

<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
    echo "Example function.\n";
    return $retval;
}

    

[!NOTE] As of PHP 8.0.0, the list of parameters may have a trailing comma:

<?php
function foo($arg_1, $arg_2,) { }

      

Any valid PHP code may appear inside the body of a function, even other functions and class definitions.

Function names follow the same rules as other labels in PHP. A valid function name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.

ENTITY

Functions need not be defined before they are referenced, except when a function is conditionally defined as shown in the two examples below.

When a function is defined in a conditional manner such as the two examples shown. Its definition must be processed prior to being called.

Conditional functions

<?php
$makefoo = true;

/* We can't call foo() from here 
   since it doesn't exist yet,
   but we can call bar() */
if (function_exists('foo')) {
    foo();
} else {
    echo "Function foo does not exist (yet).\n";
}

bar();

if ($makefoo) {
  function foo()
  {
    echo "I don't exist until program execution reaches me.\n";
  }
}

/* Now we can safely call foo()
   since $makefoo evaluated to true */

if ($makefoo) foo();

function bar() 
{
  echo "I exist immediately upon program start.\n";
}

     

Functions within functions

<?php
function foo() 
{
  function bar() 
  {
    echo "I don't exist until foo() is called.\n";
  }
}

/* We can't call bar() yet
   since it doesn't exist. */
if (function_exists('bar')) {
    bar();
}

foo();

/* Now we can call bar(),
   foo()'s processing has
   made it accessible. */

bar();

     

All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa.

PHP does not support function overloading, nor is it possible to undefine or redefine previously-declared functions.

[!NOTE] Function names are case-insensitive for the ASCII characters A to Z, though it is usually good form to call functions as they appear in their declaration.

Both variable number of arguments and default arguments are supported in functions. See also the function references for func_num_args, func_get_arg, and func_get_args for more information.

It is possible to call recursive functions in PHP.

Recursive functions

<?php
function recursion($a)
{
    if ($a < 20) {
        echo "$a\n";
        recursion($a + 1);
    }
}

recursion(17);

     

[!NOTE] Recursive function/method calls with over 100-200 recursion levels can smash the stack and cause a termination of the current script. Especially, infinite recursion is considered a programming error.

Function parameters and arguments

The function parameters are declared in the function signature. Information may be passed to functions via the argument list, which is a comma-delimited list of expressions. The arguments are evaluated from left to right and the result is assigned to the parameters of the function, before the function is actually called (eager evaluation).

PHP supports passing arguments by value (the default), passing by reference, and default argument values. Variable-length argument lists and Named Arguments are also supported.

[!NOTE] As of PHP 7.3.0, it is possible to have a trailing comma in the argument list for a function calls:

<?php
$v = foo(
    $arg_1,
    $arg_2,
);

      

As of PHP 8.0.0, the list of function parameters may include a trailing comma, which will be ignored. That is particularly useful in cases where the list of parameters is long or contains long variable names, making it convenient to list parameters vertically.

Function parameter list with trailing comma

<?php
function takes_many_args(
    $first_arg,
    $second_arg,
    $a_very_long_argument_name,
    $arg_with_default = 5,
    $again = 'a default string', // This trailing comma was not permitted before 8.0.0.
)
{
    // ...
}

    

Passing arguments by reference

By default, function arguments are passed by value (so that if the value of the argument within the function is changed, it does not get changed outside of the function). To allow a function to modify its arguments, they must be passed by reference.

To have an argument to a function always passed by reference, prepend an ampersand (ENTITY) to the parameter name in the function definition:

Passing function arguments by reference

<?php
function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'

      

It is an error to pass a constant expression as an argument to a parameter that expects to be passed by reference.

Default parameter values

A function may define default values for parameters using syntax similar to assigning a variable. The default is used only when the parameter's argument is not passed. Note that passing ENTITY does not assign the default value.

Use of default parameters in functions

<?php
function makecoffee($type = "cappuccino")
{
    return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");

      

ENTITY

Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.

Default parameter values may be scalar values, arrays, the special type ENTITY, and as of PHP 8.1.0, objects using the new ClassName() syntax.

Using non-scalar types as default values

<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
    $device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
    return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");

      

ENTITY

Making a cup of cappuccino with hands.
Making a cup of cappuccino, lavazza with teapot.

Using objects as default values (as of PHP 8.1.0)

<?php
class DefaultCoffeeMaker {
    public function brew() {
        return "Making coffee.\n";
    }
}
class FancyCoffeeMaker {
    public function brew() {
        return "Crafting a beautiful coffee just for you.\n";
    }
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
    return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);

      

ENTITY

Making coffee.
Crafting a beautiful coffee just for you.

The default value must be a constant expression, not (for example) a variable, a class member or a function call.

Note that any optional parameters should be specified after any required parameters, otherwise they cannot be omitted from calls. Consider the following example:

Incorrect usage of default function parameters

<?php
function makeyogurt($container = "bowl", $flavour)
{
    return "Making a $container of $flavour yogurt.\n";
}

echo makeyogurt("raspberry"); // "raspberry" is $container, not $flavour

      

ENTITY

Deprecated: makeyogurt(): Optional parameter $container declared before required parameter $flavour is implicitly treated as a required parameter in script on line 2

Fatal error: Uncaught ArgumentCountError: Too few arguments to function makeyogurt(), 1 passed in script on line 7 and exactly 2 expected in script:2
Stack trace:
#0 script(7): makeyogurt('raspberry')
#1 {main}
  thrown in script on line 2

Now, compare the above with this:

Correct usage of default function parameters

<?php
function makeyogurt($flavour, $container = "bowl")
{
    return "Making a $container of $flavour yogurt.\n";
}

echo makeyogurt("raspberry"); // "raspberry" is $flavour

      

ENTITY

Making a bowl of raspberry yogurt.

As of PHP 8.0.0, named arguments can be used to skip over multiple optional parameters.

Correct usage of default function parameters

<?php
function makeyogurt($container = "bowl", $flavour = "raspberry", $style = "Greek")
{
    return "Making a $container of $flavour $style yogurt.\n";
}

echo makeyogurt(style: "natural");

      

ENTITY

Making a bowl of raspberry natural yogurt.

As of PHP 8.0.0, declaring mandatory parameters after optional parameters is deprecated. This can generally be resolved by dropping the default value, since it will never be used. One exception to this rule are parameters of the form Type $param = null, where the ENTITY default makes the type implicitly nullable. This usage is deprecated as of PHP 8.4.0, and an explicit nullable type should be used instead.

Declaring optional parameters after mandatory parameters

<?php
function foo($a = [], $b) {}     // Default not used; deprecated as of PHP 8.0.0
function foo($a, $b) {}          // Functionally equivalent, no deprecation notice

function bar(A $a = null, $b) {} // As of PHP 8.1.0, $a is implicitly required
                                 // (because it comes before the required one),
                                 // but implicitly nullable (deprecated as of PHP 8.4.0),
                                 // because the default parameter value is null
function bar(?A $a, $b) {}       // Recommended

      

[!NOTE] As of PHP 7.1.0, omitting a parameter which does not specify a default throws an ArgumentCountError; in previous versions it raised a Warning.

[!NOTE] Parameters that expect the argument by reference may have a default value.

Variable-length argument lists

PHP has support for variable-length argument lists in user-defined functions by using the ... token.

Parameter lists may include the ... token to denote that the function accepts a variable number of arguments. The arguments will be passed into the given variable as an ENTITY:

Using ... to access variable arguments

<?php
function sum(...$numbers) {
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}

echo sum(1, 2, 3, 4);

      

ENTITY

10

... can also be used when calling functions to unpack an array or Traversable variable or literal into the argument list:

Using ... to provide arguments

<?php
function add($a, $b) {
    return $a + $b;
}

echo add(...[1, 2])."\n";

$a = [1, 2];
echo add(...$a);

      

ENTITY

3
3

You may specify normal positional parameters before the ... token. In this case, only the trailing arguments that don't match a positional argument will be added to the array generated by ....

It is also possible to add a type declaration before the ... token. If this is present, then all arguments captured by ... must match that parameter type.

Type declared variable arguments

<?php
function total_intervals($unit, DateInterval ...$intervals) {
    $time = 0;
    foreach ($intervals as $interval) {
        $time += $interval->$unit;
    }
    return $time;
}

$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';

// This will fail, since null isn't a DateInterval object.
echo total_intervals('d', null);

      

ENTITY

3 days
Fatal error: Uncaught TypeError: total_intervals(): Argument #2 must be of type DateInterval, null given, called in script on line 15 and defined in script:2
Stack trace:
#0 script(15): total_intervals('d', NULL)
#1 {main}
  thrown in script on line 2

Finally, variable arguments can also be passed by reference by prefixing the ... with an ampersand (ENTITY).

Named Arguments

PHP 8.0.0 introduced named arguments as an extension of the existing positional parameters. Named arguments allow passing arguments to a function based on the parameter name, rather than the parameter position. This makes the meaning of the argument self-documenting, makes the arguments order-independent and allows skipping default values arbitrarily.

Named arguments are passed by prefixing the value with the parameter name followed by a colon. Using reserved keywords as parameter names is allowed. The parameter name must be an identifier, specifying dynamically is not allowed.

Named argument syntax

<?php
myFunction(paramName: $value);
array_foobar(array: $value);

// NOT supported.
function_name($variableStoringParamName: $value);

     

Positional arguments versus named arguments

<?php
// Using positional arguments:
array_fill(0, 100, 50);

// Using named arguments:
array_fill(start_index: 0, count: 100, value: 50);

     

The order in which the named arguments are passed does not matter.

Same example as above with a different order of parameters

<?php
array_fill(value: 50, count: 100, start_index: 0);

     

Named arguments can be combined with positional arguments. In this case, the named arguments must come after the positional arguments. It is also possible to specify only some of the optional arguments of a function, regardless of their order.

Combining named arguments with positional arguments

<?php
htmlspecialchars($string, double_encode: false);
// Same as
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);

     

Passing an argument to the same named parameter multiple times results in an Error exception.

Error thrown when passing an argument to the same named parameter multiple times

<?php
function foo($param) { ... }

foo(param: 1, param: 2);
// Error: Named parameter $param overwrites previous argument

foo(1, param: 2);
// Error: Named parameter $param overwrites previous argument

     

As of PHP 8.1.0, it is possible to use named arguments after unpacking the arguments. A named argument must not override an already unpacked argument.

Use named arguments after unpacking

<?php
function foo($a, $b, $c = 3, $d = 4) {
  return $a + $b + $c + $d;
}

var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46

var_dump(foo(...[1, 2], b: 20)); // Fatal error. Named parameter $b overwrites previous argument

     

Some internal functions document an alternative signature, such as session_set_save_handler, whose parameter names do not exist in the function itself. These names cannot be used as named arguments and result in an error.

Returning values

Values are returned by using the optional return statement. Any type may be returned, including arrays and objects. This causes the function to end its execution immediately and pass control back to the line from which it was called. See return for more information.

[!NOTE] If the return is omitted the value ENTITY will be returned.

Use of return

Use of return

<?php
function square($num)
{
    return $num * $num;
}
echo square(4);   // outputs '16'.

      

A function can not return multiple values, but similar results can be obtained by returning an array.

Returning an array to get multiple values

<?php
function small_numbers()
{
    return [0, 1, 2];
}
// Array destructuring will collect each member of the array individually
[$zero, $one, $two] = small_numbers();
var_dump($zero, $one, $two);

// Prior to 7.1.0, the only equivalent alternative is using list() construct
list($zero, $one, $two) = small_numbers();

      

To return a reference from a function, use the reference operator ENTITY in both the function declaration and when assigning the returned value to a variable:

Returning a reference from a function

<?php
function &returns_reference()
{
    return $someref;
}

$newref =& returns_reference();

      

For more information on references, please check out References Explained.

Variable functions

PHP supports the concept of variable functions. This means that if a variable name has parentheses appended to it, PHP will look for a function with the same name as whatever the variable evaluates to, and will attempt to execute it. Among other things, this can be used to implement callbacks, function tables, and so forth.

Variable functions won't work with language constructs such as echo, print, unset, isset, empty, include, require and the like. Utilize wrapper functions to make use of any of these constructs as variable functions.

Variable function example

<?php
function foo() {
    echo "In foo()\n";
}

function bar($arg = '')
{
    echo "In bar(); argument was '$arg'.\n";
}

// This is a wrapper function around echo
function echoit($string)
{
    echo $string;
}

$func = 'foo';
$func();        // This calls foo()

$func = 'bar';
$func('test');  // This calls bar()

$func = 'echoit';
$func('test');  // This calls echoit()

     

Object methods can also be called with the variable functions syntax.

Variable method example

<?php
class Foo
{
    function Variable()
    {
        $name = 'Bar';
        $this->$name(); // This calls the Bar() method
    }
    
    function Bar()
    {
        echo "This is Bar";
    }
}

$foo = new Foo();
$funcname = "Variable";
$foo->$funcname();  // This calls $foo->Variable()

     

When calling static methods, the function call is stronger than the static property operator:

Variable method example with static properties

<?php
class Foo
{
    static $variable = 'static property';
    static function Variable()
    {
        echo "Method Variable called\n";
    }
}

echo Foo::$variable ."\n"; // This prints 'static property'. It does need a $variable in this scope.
$variable = "Variable";
Foo::$variable();  // This calls $foo->Variable() reading $variable in this scope.

     

ENTITY

static property
Method Variable called

Complex callables

<?php
class Foo
{
    static function bar()
    {
        echo "bar\n";
    }
    function baz()
    {
        echo "baz\n";
    }
}

$func = array("Foo", "bar");
$func(); // prints "bar"
$func = array(new Foo, "baz");
$func(); // prints "baz"
$func = "Foo::bar";
$func(); // prints "bar"

     

ENTITY

is_callable, call_user_func, function_exists, variable variables

Internal (built-in) functions

PHP comes standard with many functions and constructs. There are also functions that require specific PHP extensions compiled in, otherwise fatal "undefined function" errors will appear. For example, to use image functions such as imagecreatetruecolor, PHP must be compiled with GD support. Or, to use mysqli_connect, PHP must be compiled with MySQLi support. There are many core functions that are included in every version of PHP, such as the string and variable functions. A call to phpinfo or get_loaded_extensions will show which extensions are loaded into PHP. Also note that many extensions are enabled by default and that the PHP manual is split up by extension. See the configuration, installation, and individual extension chapters, for information on how to set up PHP.

Reading and understanding a function's prototype is explained within the manual section titled how to read a function definition. It's important to realize what a function returns or if a function works directly on a passed in value. For example, str_replace will return the modified string while usort works on the actual passed in variable itself. Each manual page also has specific information for each function like information on function parameters, behavior changes, return values for both success and failure, and availability information. Knowing these important (yet often subtle) differences is crucial for writing correct PHP code.

[!NOTE] If the parameters given to a function are not what it expects, such as passing an array where a string is expected, the return value of the function is undefined. In this case it will likely return ENTITY but this is just a convention, and cannot be relied upon. As of PHP 8.0.0, a TypeError exception is supposed to be thrown in this case.

[!NOTE] Scalar types for built-in functions are nullable by default in coercive mode. As of PHP 8.1.0, passing ENTITY to an internal function parameter that is not declared nullable is discouraged and emits a deprecation notice in coercive mode to align with the behavior of user-defined functions, where scalar types need to be marked as nullable explicitly.

For example, strlen function expects the parameter $string to be a non-nullable ENTITY. For historical reasons, PHP allows passing ENTITY for this parameter in coercive mode, and the parameter is implicitly cast to string, resulting in a "" value. In contrast, a TypeError is emitted in strict mode.

<?php
var_dump(strlen(null));
// "Deprecated: Passing null to parameter #1 ($string) of type string is deprecated" as of PHP 8.1.0
// int(0)

var_dump(str_contains("foobar", null));
// "Deprecated: Passing null to parameter #2 ($needle) of type string is deprecated" as of PHP 8.1.0
// bool(true)

     

ENTITY

function_exists, the function reference, get_extension_funcs, dl

Anonymous functions

Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callable parameters, but they have many other uses.

Anonymous functions are implemented using the Closure class.

Anonymous function example

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld

    

Closures can also be used as the values of variables; PHP automatically converts such expressions into instances of the Closure internal class. Assigning a closure to a variable uses the same syntax as any other assignment, including the trailing semicolon:

Anonymous function variable assignment example

<?php
$greet = function($name) {
    printf("Hello %s\r\n", $name);
};

$greet('World');
$greet('PHP');

    

Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct. As of PHP 7.1, these variables must not include ENTITY, $this, or variables with the same name as a parameter. A return type declaration of the function has to be placed after the use clause.

Inheriting variables from the parent scope

<?php
// A variable defined in the parent scope
$message = 'hello';

// $message is not inherited and is undefined due to the
// lack of a "use" clause
$example = function () {
    var_dump($message);
};
$example();

// $message is inherited from the parent scope due to the
// "use" clause
$example = function () use ($message) {
    var_dump($message);
};
$example();

// Inherited variable's value is from when the function
// is defined, not when called
$message = 'world';
$example();

// Reset $message
$message = 'hello';

// Inheriting by reference: a change made in the parent scope
// after the closure is defined is visible inside it
$example = function () use (&$message) {
    var_dump($message);
};
$example();

$message = 'world';
$example();

// Closures can also accept regular arguments
$example = function ($arg) use ($message) {
    var_dump($arg . ' ' . $message);
};
$example("hello");

// Closures can return values like any other function; the
// return type declaration comes after the use clause
$example = function () use ($message): array {
    return ["hello", $message];
};
var_dump($example());

    

ENTITY

Warning: Undefined variable $message in script on line 8
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"
array(2) {
  [0]=>
  string(5) "hello"
  [1]=>
  string(5) "world"
}

As of PHP 8.0.0, the list of scope-inherited variables may include a trailing comma, which will be ignored.

Inheriting variables from the parent scope is not the same as using global variables. Global variables exist in the global scope, which is the same no matter what function is executing. The parent scope of a closure is the function in which the closure was declared (not necessarily the function it was called from). See the following example:

Closures and scoping

<?php
// A basic shopping cart which contains a list of added products
// and the quantity of each product. Includes a method which
// calculates the total price of the items in the cart using a
// closure as a callback.
class Cart
{
    const PRICE_BUTTER  = 1.00;
    const PRICE_MILK    = 3.00;
    const PRICE_EGGS    = 6.95;

    protected $products = array();
    
    public function add($product, $quantity)
    {
        $this->products[$product] = ($this->products[$product] ?? 0) + $quantity;
    }
    
    public function getTotal($tax)
    {
        $total = 0.00;
        
        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                    strtoupper($product));
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };
        
        array_walk($this->products, $callback);
        return round($total, 2);
    }
}

$my_cart = new Cart;

// Add some items to the cart
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// Print the total with a 5% sales tax.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29

    

Automatic binding of $this

<?php
class Test
{
    public function testing()
    {
        return function() {
            var_dump($this);
        };
    }
}

$object = new Test;
$function = $object->testing();
$function();

    

ENTITY

object(Test)#1 (0) {
}

When declared in the context of a class, the current class is automatically bound to it, making $this available inside of the function's scope. If this automatic binding of the current class is not wanted, then static anonymous functions may be used instead.

Static anonymous functions

Anonymous functions may be declared statically. This prevents them from having the current class automatically bound to them. Objects may also not be bound to them at runtime.

Attempting to use $this inside a static anonymous function

<?php
class Foo
{
    function __construct()
    {
        $func = static function() {
            var_dump($this);
        };
        $func();
    }
};
new Foo();

      

ENTITY

Fatal error: Uncaught Error: Using $this when not in object context in script:7
Stack trace:
#0 script(9): Foo::{closure:Foo::__construct():6}()
#1 script(12): Foo->__construct()
#2 {main}
  thrown in script on line 7

Attempting to bind an object to a static anonymous function

<?php
$func = static function() {
    // function body
};
$func = $func->bindTo(new stdClass);
$func();

      

ENTITY

Warning: Cannot bind an instance to a static closure, this will be an error in PHP 9 in script on line 5

Fatal error: Uncaught Error: Value of type null is not callable in script:6
Stack trace:
#0 {main}
  thrown in script on line 6

ENTITY

ENTITY ENTITY
8.5.0 Closures can now be used in constant expressions (e.g. default property values, attribute parameters, constants).
8.3.0 Closures created from magic methods can accept named parameters.
7.1.0 Anonymous functions may not close over ENTITY, $this, or any variable with the same name as a parameter.

ENTITY

[!NOTE] It is possible to use func_num_args, func_get_arg, and func_get_args from within a closure.

Arrow Functions

Arrow functions were introduced in PHP 7.4 as a more concise syntax for anonymous functions.

Both anonymous functions and arrow functions are implemented using the Closure class.

Arrow functions have the basic form fn (argument_list) =ENTITY expr.

Arrow functions support the same features as anonymous functions, except that using variables from the parent scope is always automatic.

When a variable used in the expression is defined in the parent scope it will be implicitly captured by-value. In the following example, the functions $fn1 and $fn2 behave the same way.

Arrow functions capture variables by value automatically

<?php
$y = 1;

$fn1 = fn($x) => $x + $y;
// equivalent to using $y by value:
$fn2 = function ($x) use ($y) {
    return $x + $y;
};

var_export($fn1(3));

     

ENTITY

4

This also works if the arrow functions are nested:

Arrow functions capture variables by value automatically, even when nested

<?php
$z = 1;
$fn = fn($x) => fn($y) => $x * $y + $z;
// Outputs 51
var_export($fn(5)(10));

     

Similarly to anonymous functions, the arrow function syntax allows arbitrary function signatures, including parameter and return types, default values, variadics, as well as by-reference passing and returning. All of the following are valid examples of arrow functions:

Examples of arrow functions

<?php
fn(array $x) => $x;
static fn($x): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;

     

Arrow functions use by-value variable binding. This is roughly equivalent to performing a use($x) for every variable $x used inside the arrow function. A by-value binding means that it is not possible to modify any values from the outer scope. Anonymous functions can be used instead for by-ref bindings.

Values from the outer scope cannot be modified by arrow functions

<?php
$x = 1;
$fn = fn() => $x++; // Has no effect
$fn();
var_export($x);  // Outputs 1

     

ENTITY

ENTITY ENTITY
7.4.0 Arrow functions became available.

ENTITY

[!NOTE] It is possible to use func_num_args, func_get_arg, and func_get_args from within an arrow function.

First class callable syntax

The first class callable syntax is introduced as of PHP 8.1.0, as a way of creating anonymous functions from callable. It supersedes existing callable syntax using strings and arrays. The advantage of this syntax is that it is accessible to static analysis, and uses the scope at the point where the callable is acquired.

CallableExpr(...) syntax is used to create a Closure object from callable. CallableExpr accepts any expression that can be directly called in the PHP grammar:

Simple first class callable syntax

<?php
class Foo {
   public function method() {}
   public static function staticmethod() {}
   public function __invoke() {}
}

$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';


$f1 = strlen(...);
$f2 = $obj(...);  // invokable object
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);

// traditional callable using string, array
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);

     

[!NOTE] The ... is part of the syntax, and not an omission.

CallableExpr(...) has the same semantics as Closure::fromCallable. That is, unlike callable using strings and arrays, CallableExpr(...) respects the scope at the point where it is created:

Scope comparison of CallableExpr(...) and traditional callable

<?php
class Foo {
    public function getPrivateMethod() {
        return [$this, 'privateMethod'];
    }

    private function privateMethod() {
        echo __METHOD__, "\n";
    }
}

$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// This is because call is performed outside from Foo and visibility will be checked from this point.

     
<?php
class Foo1 {
    public function getPrivateMethod() {
        // Uses the scope where the callable is acquired.
        return $this->privateMethod(...); // identical to Closure::fromCallable([$this, 'privateMethod']);
    }

    private function privateMethod() {
        echo __METHOD__, "\n";
    }
}

$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod();  // Foo1::privateMethod

    

[!NOTE] Object creation by this syntax (e.g new Foo(...)) is not supported, because new Foo() syntax is not considered a call.

[!NOTE] The first-class callable syntax cannot be combined with the nullsafe operator. Both of the following result in a compile-time error:

<?php
$obj?->method(...);
$obj?->prop->method(...);

      

ENTITY

ENTITY ENTITY
8.5.0 First-class callables can now be used in constant expressions (e.g. default property values, attribute parameters, constants).

Generators

Generators overview

Generators provide an easy way to implement simple iterators without the overhead or complexity of implementing a class that implements the Iterator interface.

A generator offers a convenient way to provide data to ENTITY loops without having to build an array in memory ahead of time, which may cause the program to exceed a memory limit or require a considerable amount of processing time to generate. Instead, a generator function can be used, which is the same as a normal function, except that instead of returning once, a generator can ENTITY as many times as it needs to in order to provide the values to be iterated over. Like with iterators, random data access is not possible.

A simple example of this is to reimplement the range function as a generator. The standard range function has to generate an array with every value in it and return it, which can result in large arrays: for example, calling range(0, 1000000) will result in well over 10 MB of memory being used.

As an alternative, we can implement an xrange() generator, which will only ever need enough memory to create an Iterator object and track the current state of the generator internally, which turns out to be less than 1 kilobyte.

Implementing range as a generator

<?php
function xrange($start, $limit, $step = 1) {
    if ($start <= $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be positive');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be negative');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

/*
 * Note that both range() and xrange() result in the same
 * output below.
 */

echo 'Single digit odd numbers from range():  ';
foreach (range(1, 9, 2) as $number) {
    echo "$number ";
}
echo "\n";

echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
    echo "$number ";
}

   

ENTITY

Single digit odd numbers from range():  1 3 5 7 9
Single digit odd numbers from xrange(): 1 3 5 7 9

Generator objects

When a generator function is called, a new object of the internal Generator class is returned. This object implements the Iterator interface in much the same way as a forward-only iterator object would, and provides methods that can be called to manipulate the state of the generator, including sending values to and returning values from it.

Generator syntax

A generator function looks just like a normal function, except that instead of returning a value, a generator ENTITYs as many values as it needs to. Any function containing ENTITY is a generator function.

When a generator function is called, it returns an object that can be iterated over. When you iterate over that object (for instance, via a ENTITY loop), PHP will call the object's iteration methods each time it needs a value, then saves the state of the generator when the generator yields a value so that it can be resumed when the next value is required.

Once there are no more values to be yielded, then the generator can simply return, and the calling code continues just as if an array has run out of values.

[!NOTE] A generator can return values, which can be retrieved using Generator::getReturn.

yield keyword

The heart of a generator function is the yield keyword. In its simplest form, a yield statement looks much like a return statement, except that instead of stopping execution of the function and returning, yield instead provides a value to the code looping over the generator and pauses execution of the generator function.

A simple example of yielding values

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Note that $i is preserved between yields.
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}

    

ENTITY

1
2
3

[!NOTE] Internally, sequential integer keys will be paired with the yielded values, just as with a non-associative array.

Yielding values with keys

PHP also supports associative arrays, and generators are no different. In addition to yielding simple values, as shown above, you can also yield a key at the same time.

The syntax for yielding a key/value pair is very similar to that used to define an associative array, as shown below.

Yielding a key/value pair

<?php
/*
 * The input is semi-colon separated fields, with the first
 * field being an ID to use as a key.
 */

$input = <<<'EOF'
1;PHP;Likes dollar signs
2;Python;Likes whitespace
3;Ruby;Likes blocks
EOF;

function input_parser($input) {
    foreach (explode("\n", $input) as $line) {
        $fields = explode(';', $line);
        $id = array_shift($fields);

        yield $id => $fields;
    }
}

foreach (input_parser($input) as $id => $fields) {
    echo "$id:\n";
    echo "    $fields[0]\n";
    echo "    $fields[1]\n";
}

     

ENTITY

1:
    PHP
    Likes dollar signs
2:
    Python
    Likes whitespace
3:
    Ruby
    Likes blocks

Yielding null values

Yield can be called without an argument to yield a ENTITY value with an automatic key.

Yielding ENTITYs

<?php
function gen_three_nulls() {
    foreach (range(1, 3) as $i) {
        yield;
    }
}

var_dump(iterator_to_array(gen_three_nulls()));

     

ENTITY

array(3) {
  [0]=>
  NULL
  [1]=>
  NULL
  [2]=>
  NULL
}

Yielding by reference

Generator functions are able to yield values by reference as well as by value. This is done in the same way as returning references from functions: by prepending an ampersand to the function name.

Yielding values by reference

<?php
function &gen_reference() {
    $value = 3;

    while ($value > 0) {
        yield $value;
    }
}

/*
 * Note that we can change $number within the loop, and
 * because the generator is yielding references, $value
 * within gen_reference() changes.
 */
foreach (gen_reference() as &$number) {
    echo (--$number).'... ';
}

     

ENTITY

2... 1... 0...

Generator delegation via yield from

Generator delegation allows you to yield values from another generator, Traversable object, or array by using the yield from keyword. The outer generator will then yield all values from the inner generator, object, or array until that is no longer valid, after which execution will continue in the outer generator.

If a generator is used with yield from, the yield from expression will also return any value returned by the inner generator.

[!CAUTION] yield from does not reset the keys. It preserves the keys returned by the Traversable object, or array. Thus some values may share a common key with another yield or yield from, which, upon insertion into an array, will overwrite former values with that key.

A common case where this matters is iterator_to_array returning a keyed array by default, leading to possibly unexpected results. iterator_to_array has a second parameter preserve_keys which can be set to ENTITY to collect all the values while ignoring the keys returned by the Generator.

yield from with iterator_to_array

<?php
function inner() {
    yield 1; // key 0
    yield 2; // key 1
    yield 3; // key 2
}
function gen() {
    yield 0; // key 0
    yield from inner(); // keys 0-2
    yield 4; // key 1
}
// pass false as second parameter to get an array [0, 1, 2, 3, 4]
var_dump(iterator_to_array(gen()));

       

ENTITY

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(4)
  [2]=>
  int(3)
}

Basic use of yield from

<?php
function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    yield 9;
    yield 10;
}

function seven_eight() {
    yield 7;
    yield from eight();
}

function eight() {
    yield 8;
}

foreach (count_to_ten() as $num) {
    echo "$num ";
}

     

ENTITY

1 2 3 4 5 6 7 8 9 10

yield from and return values

<?php
function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    return yield from nine_ten();
}

function seven_eight() {
    yield 7;
    yield from eight();
}

function eight() {
    yield 8;
}

function nine_ten() {
    yield 9;
    return 10;
}

$gen = count_to_ten();
foreach ($gen as $num) {
    echo "$num ";
}
echo $gen->getReturn();

     

ENTITY

1 2 3 4 5 6 7 8 9 10

Comparing generators with Iterator objects

The primary advantage of generators is their simplicity. Much less boilerplate code has to be written compared to implementing an Iterator class, and the code is generally much more readable. For example, the following function and class are equivalent:

<?php
function getLinesFromFile($fileName) {
    if (!$fileHandle = fopen($fileName, 'r')) {
        return;
    }

    while (false !== $line = fgets($fileHandle)) {
        yield $line;
    }

    fclose($fileHandle);
}

// versus...

class LineIterator implements Iterator {
    protected $fileHandle;

    protected $line;
    protected $i;

    public function __construct($fileName) {
        if (!$this->fileHandle = fopen($fileName, 'r')) {
            throw new RuntimeException('Couldn\'t open file "' . $fileName . '"');
        }
    }

    public function rewind() {
        fseek($this->fileHandle, 0);
        $this->line = fgets($this->fileHandle);
        $this->i = 0;
    }

    public function valid() {
        return false !== $this->line;
    }

    public function current() {
        return $this->line;
    }

    public function key() {
        return $this->i;
    }

    public function next() {
        if (false !== $this->line) {
            $this->line = fgets($this->fileHandle);
            $this->i++;
        }
    }

    public function __destruct() {
        fclose($this->fileHandle);
    }
}

   

This flexibility does come at a cost, however: generators are forward-only iterators, and cannot be rewound once iteration has started. This also means that the same generator can't be iterated over multiple times: the generator will need to be rebuilt by calling the generator function again.

ENTITY

Object Iteration

Namespaces

Namespaces overview

What are namespaces? In the broadest definition namespaces are a way of encapsulating items. This can be seen as an abstract concept in many places. For example, in any operating system directories serve to group related files, and act as a namespace for the files within them. As a concrete example, the file foo.txt can exist in both directory /home/greg and in /home/other, but two copies of foo.txt cannot co-exist in the same directory. In addition, to access the foo.txt file outside of the /home/greg directory, we must prepend the directory name to the file name using the directory separator to get /home/greg/foo.txt. This same principle extends to namespaces in the programming world.

In the PHP world, namespaces are designed to solve two problems that authors of libraries and applications encounter when creating re-usable code elements such as classes or functions:

  1. Name collisions between code you create, and internal PHP classes/functions/constants or third-party classes/functions/constants.

  2. Ability to alias (or shorten) Extra_Long_Names designed to alleviate the first problem, improving readability of source code.

PHP Namespaces provide a way in which to group related classes, interfaces, functions and constants. Here is an example of namespace syntax in PHP:

Namespace syntax example

   
<?php
namespace my\name; // see "Defining Namespaces" section

class MyClass {}
function myfunction() {}
const MYCONST = 1;

$a = new MyClass;
print $a::class . "\n";
$c = new \my\name\MyClass; // see "Global Space" section
print $c::class . "\n";

$a = strlen('hi'); // see "Using namespaces: fallback to global
                   // function/constant" section
print $a . "\n";

$d = namespace\MYCONST; // see "namespace operator and __NAMESPACE__
                        // constant" section
print $d . "\n";
$d = __NAMESPACE__ . '\MYCONST';
echo constant($d); // see "Namespaces and dynamic language features" section
    
   

[!NOTE] Namespace names are case-insensitive.

[!NOTE] The Namespace name PHP, and compound names starting with this name (like PHP\Classes) are reserved for internal language use and should not be used in the userspace code.

Defining namespaces

Although any valid PHP code can be contained within a namespace, only the following types of code are affected by namespaces: classes (including abstract classes, traits and enums), interfaces, functions and constants.

Namespaces are declared using the namespace keyword. A file containing a namespace must declare the namespace at the top of the file before any other code - with one exception: the ??? keyword.

Declaring a single namespace

     
<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

    

[!NOTE] Fully qualified names (i.e. names starting with a backslash) are not allowed in namespace declarations, because such constructs are interpreted as relative namespace expressions.

The only code construct allowed before a namespace declaration is the declare statement, for defining encoding of a source file. In addition, no non-PHP code may precede a namespace declaration, including extra whitespace:

Declaring a single namespace

     
<html>
<?php
namespace MyProject; // fatal error - namespace must be the first statement in the script

    

In addition, unlike any other PHP construct, the same namespace may be defined in multiple files, allowing splitting up of a namespace's contents across the filesystem.

Declaring sub-namespaces

Much like directories and files, PHP namespaces also contain the ability to specify a hierarchy of namespace names. Thus, a namespace name can be defined with sub-levels:

Declaring a single namespace with hierarchy

     
<?php
namespace MyProject\Sub\Level;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }

    

The above example creates constant MyProject\Sub\Level\CONNECT_OK, class MyProject\Sub\Level\Connection and function MyProject\Sub\Level\connect.

Defining multiple namespaces in the same file

Multiple namespaces may also be declared in the same file. There are two allowed syntaxes.

Declaring multiple namespaces, simple combination syntax

     
<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }

namespace AnotherProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }

    

This syntax is not recommended for combining namespaces into a single file. Instead it is recommended to use the alternate bracketed syntax.

Declaring multiple namespaces, bracketed syntax

     
<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
}

namespace AnotherProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
}

    

It is strongly discouraged as a coding practice to combine multiple namespaces into the same file. The primary use case is to combine multiple PHP scripts into the same file.

To combine global non-namespaced code with namespaced code, only bracketed syntax is supported. Global code should be encased in a namespace statement with no namespace name as in:

Declaring multiple namespaces and unnamespaced code

     
<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection {
    public static function start() {
        print __METHOD__ . "\n";
    }
}

function connect() {
    print __FUNCTION__ . "\n";
}
}

namespace { // global code
print strlen("hi") . "\n";
MyProject\connect();
MyProject\Connection::start();
}

    

No PHP code may exist outside of the namespace brackets except for an opening declare statement.

Declaring multiple namespaces and unnamespaced code

     
<?php
declare(strict_types=1);
namespace MyProject {

const CONNECT_OK = 1;
class Connection {
    public static function start() {
        print __METHOD__ . "\n";
    }
}

function connect() {
    print __FUNCTION__ . "\n";
}
}

namespace { // global code
print strlen("hi") . "\n";
MyProject\connect();
MyProject\Connection::start();
}

    

Using namespaces: Basics

Before discussing the use of namespaces, it is important to understand how PHP knows which namespaced element your code is requesting. A simple analogy can be made between PHP namespaces and a filesystem. There are three ways to access a file in a file system:

  1. Relative file name like foo.txt. This resolves to currentdirectory/foo.txt where currentdirectory is the directory currently occupied. So if the current directory is /home/foo, the name resolves to /home/foo/foo.txt.

  2. Relative path name like subdirectory/foo.txt. This resolves to currentdirectory/subdirectory/foo.txt.

  3. Absolute path name like /main/foo.txt. This resolves to /main/foo.txt.

The same principle can be applied to namespaced elements in PHP. For example, a class name can be referred to in three ways:

  1. Unqualified name, or an unprefixed class name like $a = new foo(); or foo::staticmethod();. If the current namespace is currentnamespace, this resolves to currentnamespace\foo. If the code is global, non-namespaced code, this resolves to foo.

    One caveat: unqualified names for functions and constants will resolve to global functions and constants if the namespaced function or constant is not defined. See Using namespaces: fallback to global function/constant for details.

  2. Qualified name, or a prefixed class name like $a = new subnamespace\foo(); or subnamespace\foo::staticmethod();. If the current namespace is currentnamespace, this resolves to currentnamespace\subnamespace\foo. If the code is global, non-namespaced code, this resolves to subnamespace\foo.

  3. Fully qualified name, or a prefixed name with global prefix operator like $a = new \currentnamespace\foo(); or \currentnamespace\foo::staticmethod();. This always resolves to the literal name specified in the code, currentnamespace\foo.

Here is an example of the three kinds of syntax in actual code:

file1.php

     
<?php
namespace Foo\Bar\subnamespace;

const FOO = 1;
function foo() {}
class foo
{
    static function staticmethod() {}
}
     
    

file2.php

     
<?php
namespace Foo\Bar;
include 'file1.php';

const FOO = 2;
function foo() {}
class foo
{
    static function staticmethod() {}
}

/* Unqualified name */
foo(); // resolves to function Foo\Bar\foo
foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO

/* Qualified name */
subnamespace\foo(); // resolves to function Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // resolves to class Foo\Bar\subnamespace\foo,
                                  // method staticmethod
echo subnamespace\FOO; // resolves to constant Foo\Bar\subnamespace\FOO

/* Fully qualified name */
\Foo\Bar\foo(); // resolves to function Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo \Foo\Bar\FOO; // resolves to constant Foo\Bar\FOO
     
    

Note that to access any global class, function or constant, a fully qualified name can be used, such as \strlen or \Exception or \INI_ALL.

Accessing global classes, functions and constants from within a namespace

     
<?php
namespace Foo;

function strlen() {}
const INI_ALL = 3;
class Exception {}

print \strlen('hi') . "\n"; // calls global function strlen
print \INI_ALL . "\n"; // accesses global constant INI_ALL
$c = new \Exception('error'); // instantiates global class Exception
print $c::class . "\n";
     
    

Namespaces and dynamic language features

PHP's implementation of namespaces is influenced by its dynamic nature as a programming language. Thus, to convert code like the following example into namespaced code:

Dynamically accessing elements

example1.php:

     
<?php
class classname
{
    function __construct()
    {
        echo __METHOD__,"\n";
    }
}
function funcname()
{
    echo __FUNCTION__,"\n";
}
const constname = "global";

$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
    
    

One must use the fully qualified name (class name with namespace prefix). Note that because there is no difference between a qualified and a fully qualified Name inside a dynamic class name, function name, or constant name, the leading backslash is not necessary.

Dynamically accessing namespaced elements

     
<?php
namespace namespacename;
class classname
{
    function __construct()
    {
        echo __METHOD__,"\n";
    }
}
function funcname()
{
    echo __FUNCTION__,"\n";
}
const constname = "namespaced";

/* note that if using double quotes, "\\namespacename\\classname" must be used */
$a = '\namespacename\classname';
$obj = new $a; // prints namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // also prints namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // prints namespacename\funcname
$b = '\namespacename\funcname';
$b(); // also prints namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // prints namespaced
echo constant('namespacename\constname'), "\n"; // also prints namespaced
    
    

Be sure to read the note about escaping namespace names in strings.

The namespace keyword and __NAMESPACE__ magic constant

PHP supports two ways of abstractly accessing elements within the current namespace, the __NAMESPACE__ magic constant, and the namespace keyword.

The value of __NAMESPACE__ is a string that contains the current namespace name. In global, un-namespaced code, it contains an empty string.

__NAMESPACE__ example, namespaced code

     
<?php
namespace MyProject;

echo '"', __NAMESPACE__, '"'; // outputs "MyProject"

    

__NAMESPACE__ example, global code

     
<?php
echo '"', __NAMESPACE__, '"'; // outputs ""

    

The __NAMESPACE__ constant is useful for dynamically constructing names, for instance:

using __NAMESPACE__ for dynamic name construction

     
<?php
namespace MyProject;

function get($classname)
{
    $a = __NAMESPACE__ . '\\' . $classname;
    return new $a;
}

    

The namespace keyword can be used to explicitly request an element from the current namespace or a sub-namespace. It is the namespace equivalent of the self operator for classes.

the namespace operator, inside a namespace

     
<?php
namespace MyProject;

use blah\blah as mine; // see "Using namespaces: Aliasing/Importing"

blah\mine(); // calls function MyProject\blah\mine()
namespace\blah\mine(); // calls function MyProject\blah\mine()

namespace\func(); // calls function MyProject\func()
namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b

    

the namespace operator, in global code

     
<?php

namespace\func(); // calls function func()
namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname
$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b

    

Using namespaces: Aliasing/Importing

The ability to refer to an external fully qualified name with an alias, or importing, is an important feature of namespaces. This is similar to the ability of unix-based filesystems to create symbolic links to a file or to a directory.

PHP can alias(/import) constants, functions, classes, interfaces, traits, enums and namespaces.

Aliasing is accomplished with the use operator. Here is an example showing all 5 kinds of importing:

importing/aliasing with the use operator

     
<?php
namespace foo;
use My\Full\Classname as Another;

// this is the same as use My\Full\NSname as NSname
use My\Full\NSname;

// importing a global class
use ArrayObject;

// importing a function
use function My\Full\functionName;

// aliasing a function
use function My\Full\functionName as func;

// importing a constant
use const My\Full\CONSTANT;

$obj = new namespace\Another; // instantiates object of class foo\Another
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT

    

Note that for namespaced names (fully qualified namespace names containing namespace separator, such as Foo\Bar as opposed to global names that do not, such as FooBar), the leading backslash is unnecessary and not recommended, as import names must be fully qualified, and are not processed relative to the current namespace.

PHP additionally supports a convenience shortcut to place multiple use statements on the same line

importing/aliasing with the use operator, multiple use statements combined

     
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func

    

Importing is performed at compile-time, and so does not affect dynamic class, function or constant names.

Importing and dynamic names

     
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
$a = 'Another';
$obj = new $a;      // instantiates object of class Another

    

In addition, importing only affects unqualified and qualified names. Fully qualified names are absolute, and unaffected by imports.

Importing and fully qualified names

     
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing

    

Scoping rules for importing

The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped. The following example will show an illegal use of the use keyword:

Illegal importing rule

<?php
namespace Languages;

function toGreenlandic()
{
    use Languages\Danish;

    // ...
}

     

[!NOTE] Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules.

Group use declarations

Classes, functions and constants being imported from the same ENTITY can be grouped together in a single ENTITY statement.

<?php

use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;

use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;

use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;

// is equivalent to the following grouped use declaration
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};

    

Global space

Without any namespace definition, all class and function definitions are placed into the global space - as it was in PHP before namespaces were supported. Prefixing a name with \ will specify that the name is required from the global space even in the context of the namespace.

Using global space specification

     
<?php
namespace A\B\C;

/* This function is A\B\C\fopen */
function fopen() {
     /* ... */
     $f = \fopen(...); // call global fopen
     return $f;
}
    
    

Using namespaces: fallback to the global space for functions and constants

Inside a namespace, when PHP encounters an unqualified Name in a class name, function or constant context, it resolves these with different priorities. Class names always resolve to the current namespace name. Thus to access internal or non-namespaced user classes, one must refer to them with their fully qualified Name as in:

Accessing global classes inside a namespace

     
<?php
namespace A\B\C;
class Exception extends \Exception {}

$a = new Exception('hi'); // $a is an object of class A\B\C\Exception
var_dump($a::class);
$b = new \Exception('hi'); // $b is an object of class Exception
var_dump($b::class);

$c = new ArrayObject; // fatal error, class A\B\C\ArrayObject not found
    
    

For functions and constants, PHP will fall back to global functions or constants if a namespaced function or constant does not exist.

global functions/constants fallback inside a namespace

     
<?php
namespace A\B\C;

const E_ERROR = 45;
function strlen($str)
{
    return \strlen($str) - 1;
}

echo E_ERROR, "\n"; // prints "45"
echo INI_ALL, "\n"; // prints "7" - falls back to global INI_ALL

echo strlen('hi'), "\n"; // prints "1"
if (is_array('hi')) { // prints "is not array"
    echo "is array\n";
} else {
    echo "is not array\n";
}
    
    

Name resolution rules

For the purposes of these resolution rules, here are some important definitions:

Unqualified name
This is an identifier without a namespace separator, such as Foo

Qualified name
This is an identifier with a namespace separator, such as Foo\Bar

Fully qualified name
This is an identifier with a namespace separator that begins with a namespace separator, such as \Foo\Bar. The namespace \Foo is also a fully qualified name.

Relative name
This is an identifier starting with namespace, such as namespace\Foo\Bar.

Names are resolved following these resolution rules:

  1. Fully qualified names always resolve to the name without leading namespace separator. For instance \A\B resolves to A\B.

  2. Relative names always resolve to the name with namespace replaced by the current namespace. If the name occurs in the global namespace, the namespace\ prefix is stripped. For example namespace\A inside namespace X\Y resolves to X\Y\A. The same name inside the global namespace resolves to A.

  3. For qualified names the first segment of the name is translated according to the current class/namespace import table. For example, if the namespace A\B\C is imported as C, the name C\D\E is translated to A\B\C\D\E.

  4. For qualified names, if no import rule applies, the current namespace is prepended to the name. For example, the name C\D\E inside namespace A\B, resolves to A\B\C\D\E.

  5. For unqualified names, the name is translated according to the current import table for the respective symbol type. This means that class-like names are translated according to the class/namespace import table, function names according to the function import table and constants according to the constant import table. For example, after use A\B\C; a usage such as new C() resolves to the name A\B\C(). Similarly, after use function A\B\foo; a usage such as foo() resolves to the name A\B\foo.

  6. For unqualified names, if no import rule applies and the name refers to a class-like symbol, the current namespace is prepended. For example new C() inside namespace A\B resolves to name A\B\C.

  7. For unqualified names, if no import rule applies and the name refers to a function or constant and the code is outside the global namespace, the name is resolved at runtime. Assuming the code is in namespace A\B, here is how a call to function foo() is resolved:

    1. It looks for a function from the current namespace: A\B\foo().

    2. It tries to find and call the global function foo().

Name resolutions illustrated

<?php
namespace A;
use B\D, C\E as F;

// function calls

foo();      // first tries to call "foo" defined in namespace "A"
            // then calls global function "foo"

\foo();     // calls function "foo" defined in global scope

my\foo();   // calls function "foo" defined in namespace "A\my"

F();        // first tries to call "F" defined in namespace "A"
            // then calls global function "F"

// class references

new B();    // creates object of class "B" defined in namespace "A"
            // if not found, it tries to autoload class "A\B"

new D();    // using import rules, creates object of class "D" defined in namespace "B"
            // if not found, it tries to autoload class "B\D"

new F();    // using import rules, creates object of class "E" defined in namespace "C"
            // if not found, it tries to autoload class "C\E"

new \B();   // creates object of class "B" defined in global scope
            // if not found, it tries to autoload class "B"

new \D();   // creates object of class "D" defined in global scope
            // if not found, it tries to autoload class "D"

new \F();   // creates object of class "F" defined in global scope
            // if not found, it tries to autoload class "F"

// static methods/namespace functions from another namespace

B\foo();    // calls function "foo" from namespace "A\B"

B::foo();   // calls method "foo" of class "B" defined in namespace "A"
            // if class "A\B" not found, it tries to autoload class "A\B"

D::foo();   // using import rules, calls method "foo" of class "D" defined in namespace "B"
            // if class "B\D" not found, it tries to autoload class "B\D"

\B\foo();   // calls function "foo" from namespace "B"

\B::foo();  // calls method "foo" of class "B" from global scope
            // if class "B" not found, it tries to autoload class "B"

// static methods/namespace functions of current namespace

A\B::foo();   // calls method "foo" of class "B" from namespace "A\A"
              // if class "A\A\B" not found, it tries to autoload class "A\A\B"

\A\B::foo();  // calls method "foo" of class "B" from namespace "A"
              // if class "A\B" not found, it tries to autoload class "A\B"

   

FAQ: things you need to know about namespaces

This FAQ is split into two sections: common questions, and some specifics of implementation that are helpful to understand fully.

First, the common questions.

  1. If I don't use namespaces, should I care about any of this?

  2. How do I use internal or global classes in a namespace?

  3. How do I use namespaces classes functions, or constants in their own namespace?

  4. How does a name like \my\name or \name resolve?

  5. How does a name like my\name resolve?

  6. How does an unqualified class name like name resolve?

  7. How does an unqualified function name or unqualified constant name like name resolve?

There are a few implementation details of the namespace implementations that are helpful to understand.

  1. Import names must not conflict with classes defined in the same file.

  2. Nested namespaces are not allowed.

  3. Dynamic namespace names (quoted identifiers) should escape backslash.

  4. Undefined Constants referenced using any backslash die with fatal error

  5. Cannot override special constants ENTITY, ENTITY or ENTITY

If I don't use namespaces, should I care about any of this?

No. Namespaces do not affect any existing code in any way, or any as-yet-to-be-written code that does not contain namespaces. You can write this code if you wish:

Accessing global classes outside a namespace

<?php
$a = new \stdClass;
print $a::class;

     

This is functionally equivalent to:

Accessing global classes outside a namespace

<?php
$a = new stdClass;
print $a::class;

     

How do I use internal or global classes in a namespace?

Accessing internal classes in namespaces

<?php
namespace foo;
$a = new \stdClass;
print $a::class . "\n";

function test(?\ArrayObject $parameter_type_example = null) {}

$a = \FilesystemIterator::CURRENT_AS_FILEINFO;
print $a . "\n";

// extending an internal or global class
class MyException extends \Exception {}
print MyException::class . "\n";

     

How do I use namespaces classes, functions, or constants in their own namespace?

Accessing internal classes, functions or constants in namespaces

<?php
namespace foo;

class MyClass {}

// using a class from the current namespace as a parameter type
function test(?MyClass $parameter_type_example = null) {}
// another way to use a class from the current namespace as a parameter type
function test2(?\foo\MyClass $parameter_type_example = null) {}

// extending a class from the current namespace
class Extended extends MyClass {}
print Extended::class . "\n";

// accessing a global function
$a = \strlen("test");
print $a . "\n";

// accessing a global constant
$b = \INI_ALL;
print $b . "\n";

     

How does a name like \my\name or \name resolve?

Names that begin with a \ always resolve to what they look like, so \my\name is in fact my\name, and \Exception is Exception.

Fully Qualified names

<?php
namespace foo;
$a = new \my\name(); // instantiates "my\name" class
echo \strlen('hi'); // calls function "strlen"
$a = \INI_ALL; // $a is set to the value of constant "INI_ALL"

     

How does a name like my\name resolve?

Names that contain a backslash but do not begin with a backslash like my\name can be resolved in 2 different ways.

If there is an import statement that aliases another name to my, then the import alias is applied to the my in my\name.

Otherwise, the current namespace name is prepended to my\name.

Qualified names

<?php
namespace foo;
use blah\blah as foo;

$a = new my\name(); // instantiates "foo\my\name" class
foo\bar::name(); // calls static method "name" in class "blah\blah\bar"
my\bar(); // calls function "foo\my\bar"
$a = my\BAR; // sets $a to the value of constant "foo\my\BAR"

     

How does an unqualified class name like name resolve?

Class names that do not contain a backslash like name can be resolved in 2 different ways.

If there is an import statement that aliases another name to name, then the import alias is applied.

Otherwise, the current namespace name is prepended to name.

Unqualified class names

<?php
namespace foo;
use blah\blah as foo;

$a = new name(); // instantiates "foo\name" class
foo::name(); // calls static method "name" in class "blah\blah"

     

How does an unqualified function name or unqualified constant name like name resolve?

Function or constant names that do not contain a backslash like name can be resolved in 2 different ways.

First, the current namespace name is prepended to name.

Finally, if the constant or function name does not exist in the current namespace, a global constant or function name is used if it exists.

Unqualified function or constant names

<?php
namespace foo;
use blah\blah as foo;

const FOO = 1;

function my() {
    print __FUNCTION__ . "\n";
}
function foo() {
    print __FUNCTION__ . "\n";
}
function sort(&$a)
{
    \sort($a); // calls the global function "sort"
    $a = array_flip($a);
    return $a;
}

my(); // calls "foo\my"
print strlen('hi') . "\n"; // calls global function "strlen" because "foo\strlen" does not exist
$arr = array(1,3,2);
$b = sort($arr); // calls function "foo\sort"
var_dump($b);
foo(); // calls function "foo\foo" - import is not applied

$a = FOO; // sets $a to value of constant "foo\FOO" - import is not applied
print $a;
$b = INI_ALL; // sets $b to value of global constant "INI_ALL"
print $b;

     

Import names must not conflict with classes defined in the same file.

The following script combinations are legal:

file1.php

     
<?php
namespace my\stuff;
class MyClass {}
     
     

another.php

     
<?php
namespace another;
class thing {}
     
     

file2.php

     
<?php
namespace my\stuff;
include 'file1.php';
include 'another.php';

use another\thing as MyClass;
$a = new MyClass; // instantiates class "thing" from namespace another
     
     

There is no name conflict, even though the class MyClass exists within the my\stuff namespace, because the MyClass definition is in a separate file. However, the next example causes a fatal error on name conflict because MyClass is defined in the same file as the use statement.

     
<?php
namespace my\stuff;
use another\thing as MyClass;
class MyClass {} // fatal error: MyClass conflicts with import statement
$a = new MyClass;
     
     

Nested namespaces are not allowed.

PHP does not allow nesting namespaces

     
<?php
namespace my\stuff {
    namespace nested {
        class foo {}
    }
}
     
     

However, it is easy to simulate nested namespaces like so:

     
<?php
namespace my\stuff\nested {
    class foo {}
}
     
     

Dynamic namespace names (quoted identifiers) should escape backslash

It is very important to realize that because the backslash is used as an escape character within strings, it should always be doubled when used inside a string. Otherwise there is a risk of unintended consequences:

Dangers of using namespaced names inside a double-quoted string

      
<?php
$a = "dangerous\name"; // \n is a newline inside double quoted strings!
$obj = new $a;

$a = 'not\at\all\dangerous'; // no problems here.
$obj = new $a;
      
     

Inside a single-quoted string, the backslash escape sequence is much safer to use, but it is still recommended practice to escape backslashes in all strings as a best practice.

Undefined Constants referenced using any backslash die with fatal error

Any undefined constant that is unqualified like FOO will produce a notice explaining that PHP assumed FOO was the value of the constant. Any constant, qualified or fully qualified, that contains a backslash will produce a fatal error if not found.

Undefined constants

      
<?php
namespace bar;
$a = FOO; // produces notice - undefined constants "FOO" assumed "FOO";
$a = \FOO; // fatal error, undefined namespace constant FOO
$a = Bar\FOO; // fatal error, undefined namespace constant bar\Bar\FOO
$a = \Bar\FOO; // fatal error, undefined namespace constant Bar\FOO
      
     

Cannot override special constants ENTITY, ENTITY or ENTITY

Any attempt to define a namespaced constant that is a special, built-in constant results in a fatal error

Undefined constants

      
<?php
namespace bar;
const NULL = 0; // fatal error;
const true = 'stupid'; // also fatal error;
// etc.
      
     

Classes and Objects

Introduction

PHP includes a complete object model. Some of its features are: visibility, abstract and final classes and methods, additional magic methods, interfaces, and cloning.

PHP treats objects in the same way as references or handles, meaning that each variable contains an object reference rather than a copy of the entire object. See Objects and References

ENTITY

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

Class Abstraction

PHP has abstract classes, methods, and properties. Classes defined as abstract cannot be instantiated, and any class that contains at least one abstract method or property must also be abstract. Methods defined as abstract simply declare the method's signature and whether it is public or protected; they cannot define the implementation. Properties defined as abstract may declare a requirement for get or set behavior, and may provide an implementation for one, but not both, operations.

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child class, and follow the usual inheritance and signature compatibility rules.

As of PHP 8.4, an abstract class may declare an abstract property, either public or protected. A protected abstract property may be satisfied by a property that is readable/writeable from either protected or public scope.

An abstract property may be satisfied either by a standard property or by a property with defined hooks, corresponding to the required operation.

Abstract method example

<?php

abstract class AbstractClass
{
    // Force extending class to define this method
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // Common method
    public function printOut()
    {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue()
    {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix)
    {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue()
    {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix)
    {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1();
$class1->printOut();
echo $class1->prefixValue('FOO_'), "\n";

$class2 = new ConcreteClass2();
$class2->printOut();
echo $class2->prefixValue('FOO_'), "\n";

?>

   

ENTITY

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

Abstract method example

<?php

abstract class AbstractClass
{
    // An abstract method only needs to define the required arguments
    abstract protected function prefixName($name);
}

class ConcreteClass extends AbstractClass
{
    // A child class may define optional parameters which are not present in the parent's signature
    public function prefixName($name, $separator = ".")
    {
        if ($name == "Pacman") {
            $prefix = "Mr";
        } elseif ($name == "Pacwoman") {
            $prefix = "Mrs";
        } else {
            $prefix = "";
        }

        return "{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass();
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";

?>

   

ENTITY

Mr. Pacman
Mrs. Pacwoman

Abstract property example

<?php

abstract class A
{
    // Extending classes must have a publicly-gettable property
    abstract public string $readable {
        get;
    }

    // Extending classes must have a protected- or public-writeable property
    abstract protected string $writeable {
        set;
    }

    // Extending classes must have a protected or public symmetric property
    abstract protected string $both {
        get;
        set;
    }
}

class C extends A
{
    // This satisfies the requirement and also makes it settable, which is valid
    public string $readable;

    // This would NOT satisfy the requirement, as it is not publicly readable
    protected string $readable;

    // This satisfies the requirement exactly, so is sufficient.
    // It may only be written to, and only from protected scope
    protected string $writeable {
        set => $value;
    }

    // This expands the visibility from protected to public, which is fine
    public string $both;
}

?>

   

An abstract property on an abstract class may provide implementations for any hook, but must have either get or set declared but not defined (as in the example above).

Abstract property with hooks example

<?php

abstract class A
{
    // This provides a default (but overridable) set implementation,
    // and requires child classes to provide a get implementation
    abstract public string $foo {
        get;

        set {
            $this->foo = $value;
        }
    }
}

?>
 
   

Anonymous classes

Anonymous classes are useful when simple, one-off objects need to be created.

<?php

// Using an explicit class
class Logger
{
    public function log($msg)
    {
        echo $msg;
    }
}

$util->setLogger(new Logger());

// Using an anonymous class
$util->setLogger(new class {
    public function log($msg)
    {
        echo $msg;
    }
});

  

They can pass arguments through to their constructors, extend other classes, implement interfaces, and use traits just like a normal class can:

<?php

class SomeClass {}
interface SomeInterface {}
trait SomeTrait {}

var_dump(new class(10) extends SomeClass implements SomeInterface {
    private $num;

    public function __construct($num)
    {
        $this->num = $num;
    }

    use SomeTrait;
});

  

ENTITY

object(class@anonymous)#1 (1) {
  ["Command line code0x104c5b612":"class@anonymous":private]=>
  int(10)
}

Nesting an anonymous class within another class does not give it access to any private or protected methods or properties of that outer class. In order to use the outer class' protected properties or methods, the anonymous class can extend the outer class. To use the private properties of the outer class in the anonymous class, they must be passed through its constructor:

<?php

class Outer
{
    private $prop = 1;
    protected $prop2 = 2;

    protected function func1()
    {
        return 3;
    }

    public function func2()
    {
        return new class($this->prop) extends Outer {
            private $prop3;

            public function __construct($prop)
            {
                $this->prop3 = $prop;
            }

            public function func3()
            {
                return $this->prop2 + $this->prop3 + $this->func1();
            }
        };
    }
}

echo (new Outer)->func2()->func3();

  

ENTITY

6

All objects created by the same anonymous class declaration are instances of that very class.

<?php
function anonymous_class()
{
    return new class {};
}

if (get_class(anonymous_class()) === get_class(anonymous_class())) {
    echo 'same class';
} else {
    echo 'different class';
}
 

ENTITY

same class

[!NOTE] Note that anonymous classes are assigned a name by the engine, as demonstrated in the following example. This name has to be regarded as an implementation detail, which should not be relied upon.

<?php
echo get_class(new class {});

  

ENTITY

class@anonymous/in/oNi1A0x7f8636ad2021

Readonly anonymous classes

As of PHP 8.3.0, the readonly modifier can be applied to anonymous classes.

Defining a readonly anonymous class

    
<?php
// Using an anonymous class
var_dump(new readonly class('[DEBUG]') {
    public function __construct(private string $prefix)
    {
    }

    public function log($msg)
    {
        echo $this->prefix . ' ' . $msg;
    }
});

   

Autoloading Classes

Many developers writing object-oriented applications create one PHP source file per class definition. One of the biggest annoyances is having to write a long list of needed includes at the beginning of each script (one for each class).

The spl_autoload_register function registers any number of autoloaders, enabling classes and interfaces to be automatically loaded if they are currently not defined. By registering autoloaders, PHP is given a last chance to load the class or interface before it fails with an error.

Any class-like construct may be autoloaded the same way. That includes classes, interfaces, traits, and enumerations.

[!CAUTION] Prior to PHP 8.0.0, it was possible to use __autoload to autoload classes and interfaces. However, it is a less flexible alternative to spl_autoload_register and __autoload is deprecated as of PHP 7.2.0, and removed as of PHP 8.0.0.

[!NOTE] spl_autoload_register may be called multiple times in order to register multiple autoloaders. Throwing an exception from an autoload function, however, will interrupt that process and not allow further autoload functions to run. For that reason, throwing exceptions from an autoload function is strongly discouraged.

Autoload example

This example attempts to load the classes MyClass1 and MyClass2 from the files MyClass1.php and MyClass2.php respectively.

<?php
spl_autoload_register(function ($class_name) {
    include $class_name . '.php';
});

$obj  = new MyClass1();
$obj2 = new MyClass2(); 
?>

    

Autoload other example

This example attempts to load the interface ITest.

<?php

spl_autoload_register(function ($name) {
    var_dump($name);
});

class Foo implements ITest {
}

/*
string(5) "ITest"

Fatal error: Interface 'ITest' not found in ...
*/
?>

    

Using Composer's autoloader

ENTITY generates a vendor/autoload.php which is set up to automatically load packages that are being managed by Composer. By including this file, those packages can be used without any additional work.

<?php
require __DIR__ . '/vendor/autoload.php';

$uuid = Ramsey\Uuid\Uuid::uuid7();

echo "Generated new UUID -> ", $uuid->toString(), "\n";
?>

    

ENTITY

unserialize, unserialize_callback_func, unserialize_max_depth, spl_autoload_register, spl_autoload, __autoload

The Basics

class

Basic class definitions begin with the keyword class, followed by a class name, followed by a pair of curly braces which enclose the definitions of the properties and methods belonging to the class.

The class name can be any valid label, provided it is not a PHP reserved word. As of PHP 8.4.0, using a single underscore _ as a class name is deprecated. A valid class name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.

A class may contain its own constants, variables (called "properties"), and functions (called "methods").

Simple Class definition

<?php
class SimpleClass
{
    // property declaration
    public $var = 'a default value';

    // method declaration
    public function displayVar() {
        echo $this->var;
    }
}
?>

    

The pseudo-variable $this is available when a method is called from within an object context. $this is the value of the calling object.

[!WARNING] Calling a non-static method statically throws an Error. Prior to PHP 8.0.0, this would generate a deprecation notice, and $this would be undefined.

Some examples of the $this pseudo-variable

<?php
class A
{
    function foo()
    {
        if (isset($this)) {
            echo '$this is defined (';
            echo get_class($this);
            echo ")\n";
        } else {
            echo "\$this is not defined.\n";
        }
    }
}

class B
{
    function bar()
    {
        A::foo();
    }
}

$a = new A();
$a->foo();

A::foo();

$b = new B();
$b->bar();

B::bar();
?>

     

ENTITY

$this is defined (A)

Deprecated: Non-static method A::foo() should not be called statically in %s  on line 27
$this is not defined.

Deprecated: Non-static method A::foo() should not be called statically in %s  on line 20
$this is not defined.

Deprecated: Non-static method B::bar() should not be called statically in %s  on line 32

Deprecated: Non-static method A::foo() should not be called statically in %s  on line 20
$this is not defined.

ENTITY

$this is defined (A)

Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27
Stack trace:
#0 {main}
  thrown in %s  on line 27

Readonly classes

As of PHP 8.2.0, a class can be marked with the readonly modifier. Marking a class as readonly will add the readonly modifier to every declared property, and prevent the creation of dynamic properties. Moreover, it is impossible to add support for them by using the AllowDynamicProperties attribute. Attempting to do so will trigger a compile-time error.

<?php
#[\AllowDynamicProperties]
readonly class Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

     

As neither untyped nor static properties can be marked with the readonly modifier, readonly classes cannot declare them either:

<?php
readonly class Foo
{
    public $bar;
}

// Fatal error: Readonly property Foo::$bar must have type
?>

     
<?php
readonly class Foo
{
    public static int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties
?>

     

A readonly class can be extended if, and only if, the child class is also a readonly class.

new

To create an instance of a class, the new keyword must be used. An object will always be created unless the object has a constructor defined that throws an Exception on error. Classes should be defined before instantiation (and in some cases this is a requirement).

If a variable containing a string with the name of a class is used with new, a new instance of that class will be created. If the class is in a namespace, its fully qualified name must be used when doing this.

[!NOTE] If there are no arguments to be passed to the class's constructor, parentheses after the class name may be omitted.

Creating an instance

<?php
class SimpleClass {
}

$instance = new SimpleClass();
var_dump($instance);

// This can also be done with a variable:
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
var_dump($instance);
?>

    

As of PHP 8.0.0, using new with arbitrary expressions is supported. This allows more complex instantiation if the expression produces a string. The expressions must be wrapped in parentheses.

Creating an instance using an arbitrary expression

In the given example we show multiple examples of valid arbitrary expressions that produce a class name. This shows a call to a function, string concatenation, and the ::class constant.

     
<?php

class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}

function getSomeClass(): string
{
    return 'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

    

ENTITY

object(ClassA)#1 (0) {
}
object(ClassB)#1 (0) {
}
object(ClassC)#1 (0) {
}
object(ClassD)#1 (0) {
}

In the class context, it is possible to create a new object by new self and new parent.

When assigning an already created instance of a class to a new variable, the new variable will access the same instance as the object that was assigned. This behaviour is the same when passing instances to a function. A copy of an already created object can be made by cloning it.

Object Assignment

<?php
class SimpleClass {
    public string $var;
}

$instance = new SimpleClass();

$assigned   =  $instance;
$reference  =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

    

ENTITY

NULL
NULL
object(SimpleClass)#1 (1) {
  ["var"]=>
  string(30) "$assigned will have this value"
}

It's possible to create instances of an object in a couple of ways:

Creating new objects

<?php

class Test
{
    public static function getNew()
    {
        return new static();
    }
}

class Child extends Test {}

$obj1 = new Test(); // By the class name
$obj2 = new $obj1(); // Through the variable containing an object
var_dump($obj1 !== $obj2);

$obj3 = Test::getNew(); // By the class method
var_dump($obj3 instanceof Test);

$obj4 = Child::getNew(); // Through a child class method
var_dump($obj4 instanceof Child);

?>

    

ENTITY

bool(true)
bool(true)
bool(true)

It is possible to access a member of a newly created object in a single expression:

Access member of newly created object

<?php
echo (new DateTime())->format('Y'), PHP_EOL;

// surrounding parentheses are optional as of PHP 8.4.0
echo new DateTime()->format('Y'), PHP_EOL;
?>

    

ENTITY

2025
2025

[!NOTE] Prior to PHP 7.1, the arguments are not evaluated if there is no constructor function defined.

Properties and methods

Class properties and methods live in separate "namespaces", so it is possible to have a property and a method with the same name. Referring to both a property and a method has the same notation, and whether a property will be accessed or a method will be called, solely depends on the context, i.e. whether the usage is a variable access or a function call.

Property access vs. method call

<?php
class Foo
{
    public $bar = 'property';
    
    public function bar() {
        return 'method';
    }
}

$obj = new Foo();
echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;

    

ENTITY

property
method

That means that calling an anonymous function which has been assigned to a property is not directly possible. Instead the property has to be assigned to a variable first, for instance. It is possible to call such a property directly by enclosing it in parentheses.

Calling an anonymous function stored in a property

<?php
class Foo
{
    public $bar;
    
    public function __construct() {
        $this->bar = function() {
            return 42;
        };
    }
}

$obj = new Foo();

echo ($obj->bar)(), PHP_EOL;

    

ENTITY

42

extends

A class can inherit the constants, methods, and properties of another class by using the keyword extends in the class declaration. It is not possible to extend multiple classes; a class can only inherit from one base class.

The inherited constants, methods, and properties can be overridden by redeclaring them with the same name defined in the parent class. However, if the parent class has defined a method or constant as final, they may not be overridden. It is possible to access the overridden methods or static properties by referencing them with parent::.

[!NOTE] As of PHP 8.1.0, constants may be declared as final.

Simple Class Inheritance

<?php
class SimpleClass
{
    function displayVar()
    {
        echo "Parent class\n";
    }
}

class ExtendClass extends SimpleClass
{
    // Redefine the parent method
    function displayVar()
    {
        echo "Extending class\n";
        parent::displayVar();
    }
}

$extended = new ExtendClass();
$extended->displayVar();
?>

    

ENTITY

Extending class
Parent class

Signature compatibility rules

When overriding a method, its signature must be compatible with the parent method. Otherwise, a fatal error is emitted, or, prior to PHP 8.0.0, an E_WARNING level error is generated. A signature is compatible if it respects the variance rules, makes a mandatory parameter optional, adds only optional new parameters and doesn't restrict but only relaxes the visibility. This is known as the Liskov Substitution Principle, or LSP for short. The constructor, and private methods are exempt from these signature compatibility rules, and thus won't emit a fatal error in case of a signature mismatch.

Compatible child methods

<?php

class Base
{
    public function foo(int $a) {
        echo "Valid\n";
    }
}

class Extend1 extends Base
{
    function foo(int $a = 5)
    {
        parent::foo($a);
    }
}

class Extend2 extends Base
{
    function foo(int $a, $b = 5)
    {
        parent::foo($a);
    }
}

$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);

     

ENTITY

Valid
Valid

The following examples demonstrate that a child method which removes a parameter, or makes an optional parameter mandatory, is not compatible with the parent method.

Fatal error when a child method removes a parameter

<?php

class Base
{
    public function foo(int $a = 5) {
        echo "Valid\n";
    }
}

class Extend extends Base
{
    function foo()
    {
        parent::foo(1);
    }
}

     

ENTITY

Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13

Fatal error when a child method makes an optional parameter mandatory

<?php

class Base
{
    public function foo(int $a = 5) {
        echo "Valid\n";
    }
}

class Extend extends Base
{
    function foo(int $a)
    {
        parent::foo($a);
    }
}

     

ENTITY

Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13

[!WARNING] Renaming a method's parameter in a child class is not a signature incompatibility. However, this is discouraged as it will result in a runtime Error if named arguments are used.

Error when using named arguments and parameters were renamed in a child class

<?php

class A {
    public function test($foo, $bar) {}
}

class B extends A {
    public function test($a, $b) {}
}

$obj = new B;

// Pass parameters according to A::test() contract
$obj->test(foo: "foo", bar: "bar"); // ERROR!

      

ENTITY

Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14
Stack trace:
#0 {main}
  thrown in /in/XaaeN on line 14

::class

The class keyword is also used for class name resolution. To obtain the fully qualified name of a class ClassName use ClassName::class. This is particularly useful with namespaced classes.

Class name resolution

<?php
namespace NS {
    class ClassName {
    }
    
    echo ClassName::class;
}
?>

     

ENTITY

NS\ClassName

[!NOTE] The class name resolution using ::class is a compile time transformation. That means at the time the class name string is created no autoloading has happened yet. As a consequence, class names are expanded even if the class does not exist. No error is issued in that case.

Missing class name resolution

<?php
print Does\Not\Exist::class;
?>

     

ENTITY

Does\Not\Exist

As of PHP 8.0.0, ::class may also be used on objects. This resolution happens at runtime, not compile time. Its effect is the same as calling get_class on the object.

Object name resolution

<?php
namespace NS {
    class ClassName {
    }

    $c = new ClassName();
    print $c::class;
}
?>

    

ENTITY

NS\ClassName

Nullsafe methods and properties

As of PHP 8.0.0, properties and methods may also be accessed with the "nullsafe" operator instead: ?->. The nullsafe operator works the same as property or method access as above, except that if the object being dereferenced is ENTITY then ENTITY will be returned rather than an exception thrown. If the dereference is part of a chain, the rest of the chain is skipped.

The effect is similar to wrapping each access in an is_null check first, but more compact.

Nullsafe Operator

<?php

// As of PHP 8.0.0, this line:
$result = $repository?->getUser(5)?->name;

// Is equivalent to the following code block:
if (is_null($repository)) {
    $result = null;
} else {
    $user = $repository->getUser(5);
    if (is_null($user)) {
        $result = null;
    } else {
        $result = $user->name;
    }
}
?>

    

[!NOTE] The nullsafe operator is best used when null is considered a valid and expected possible value for a property or method return. For indicating an error, a thrown exception is preferable.

OOP Changelog

Changes to the PHP OOP model are logged here. Descriptions and other notes regarding these features are documented within the OOP model documentation.

ENTITY ENTITY
8.5.0 Changed: A method that returns static may now be overridden in a final class to declare self or the class's own type as its return type, as these are equivalent to static in a class that cannot be extended further.
8.5.0 Changed: Traits are now bound to a class before its parent class.
8.4.0 Added: Support for Property Hooks.
8.4.0 Added: Support for Lazy Objects.
8.1.0 Added: Support for the final modifier for class constants. Also, interface constants become overridable by default.
8.0.0 Added: Support for the nullsafe operator ?-ENTITY to access properties and methods on objects that may be null.
7.4.0 Changed: It is now possible to throw an exception within __toString.
7.4.0 Added: Support for limited return type covariance and argument type contravariance. Full variance support is only available if autoloading is used. Inside a single file only non-cyclic type references are possible.
7.4.0 Added: It is now possible to type class properties.
7.3.0 Incompatibility: Argument unpacking of Traversables with non-ENTITY keys is no longer supported. This behaviour was not intended and thus has been removed.
7.3.0 Incompatibility: In previous versions it was possible to separate the static properties by assigning a reference. This has been removed.
7.3.0 Changed: The instanceof operator now allows literals as the first operand, in which case the result is always ENTITY.
7.2.0 Deprecated: The __autoload method has been deprecated in favour of spl_autoload_register.
7.2.0 Changed: The following name cannot be used to name classes, interfaces, or traits: object.
7.2.0 Changed: A trailing comma can now be added to the group-use syntax for namespaces.
7.2.0 Changed: Parameter type widening. Parameter types from overridden methods and from interface implementations may now be omitted.
7.2.0 Changed: Abstract methods can now be overridden when an abstract class extends another abstract class.
7.1.0 Changed: The following names cannot be used to name classes, interfaces, or traits: void and iterable.
7.1.0 Added: It is now possible to specify the visibility of class constants.
7.0.0 Deprecated: Static calls to methods that are not declared static.
7.0.0 Deprecated: PHP 4 style constructor. I.e. methods that have the same name as the class they are defined in.
7.0.0 Added: Group use declaration: classes, functions and constants being imported from the same namespace can now be grouped together in a single use statement.
7.0.0 Added: Support for anonymous classes has been added via new class.
7.0.0 Incompatibility: Iterating over a non-Traversable ENTITY will now have the same behaviour as iterating over by-reference ENTITYs.
7.0.0 Changed: Defining (compatible) properties in two used traits no longer triggers an error.
5.6.0 Added: The __debugInfo() method.
5.5.0 Added: The ::class magic constant.
5.5.0 Added: finally to handle exceptions.
5.4.0 Added: traits.
5.4.0 Changed: If an abstract class defines a signature for the constructor it will now be enforced.
5.3.3 Changed: Methods with the same name as the last element of a namespaced class name will no longer be treated as constructor. This change doesn't affect non-namespaced classes.
5.3.0 Changed: Classes that implement interfaces with methods that have default values in the prototype are no longer required to match the interface's default value.
5.3.0 Changed: It's now possible to reference the class using a variable (e.g., echo $classname::constant;). The variable's value can not be a keyword (e.g., self, parent or static).
5.3.0 Changed: An E_WARNING level error is issued if the magic overloading methods are declared static. It also enforces the public visibility requirement.
5.3.0 Changed: Prior to 5.3.0, exceptions thrown in the __autoload function could not be caught in the catch block, and would result in a fatal error. Exceptions now thrown in the __autoload function can be caught in the catch block, with one provision. If throwing a custom exception, then the custom exception class must be available. The __autoload function may be used recursively to autoload the custom exception class.
5.3.0 Added: The __callStatic method.
5.3.0 Added: heredoc and nowdoc support for class const and property definitions. Note: heredoc values must follow the same rules as double-quoted strings, (e.g. no variables within).
5.3.0 Added: Late Static Bindings.
5.3.0 Added: The __invoke() method.
5.2.0 Changed: The __toString() method was only called when it was directly combined with echo or print. But now, it is called in any ENTITY context (e.g. in printf with %s modifier) but not in other type contexts (e.g. with %d modifier). As of PHP 5.2.0, converting ENTITYs without a __toString method to ENTITY emits a E_RECOVERABLE_ERROR level error.
5.1.3 Changed: In previous versions of PHP 5, the use of var was considered deprecated and would issue an E_STRICT level error. It's no longer deprecated, therefore does not emit the error.
5.1.0 Changed: The __set_state() static method is now called for classes exported by var_export.
5.1.0 Added: The __isset() and __unset() methods.

Object Cloning

Creating a copy of an object with fully replicated properties is not always the wanted behavior. A good example of the need for copy constructors is if you have an object which represents a GTK window and the object holds the resource of this GTK window, when you create a duplicate you might want to create a new window with the same properties and have the new object hold the resource of the new window. Another example is if your object holds a reference to another object which it uses and when you replicate the parent object you want to create a new instance of this other object so that the replica has its own separate copy.

An object copy is created by using the clone keyword (which calls the object's __clone() method if possible).

$copy_of_object = clone $object;

When an object is cloned, PHP will perform a shallow copy of all of the object's properties. Any properties that are references to other variables will remain references.

void

__clone

Once the cloning is complete, if a __clone() method is defined, then the newly created object's __clone() method will be called, to allow any necessary properties to be changed.

Cloning an object

<?php
class SubObject
{
    static $instances = 0;
    public $instance;

    public function __construct() {
        $this->instance = ++self::$instances;
    }

    public function __clone() {
        $this->instance = ++self::$instances;
    }
}

class MyCloneable
{
    public $object1;
    public $object2;

    function __clone()
    {
        // Force a copy of this->object, otherwise
        // it will point to same object.
        $this->object1 = clone $this->object1;
    }
}

$obj = new MyCloneable();

$obj->object1 = new SubObject();
$obj->object2 = new SubObject();

$obj2 = clone $obj;


print "Original Object:\n";
print_r($obj);

print "Cloned Object:\n";
print_r($obj2);

?> 

   

ENTITY

Original Object:
MyCloneable Object
(
    [object1] => SubObject Object
        (
            [instance] => 1
        )

    [object2] => SubObject Object
        (
            [instance] => 2
        )

)
Cloned Object:
MyCloneable Object
(
    [object1] => SubObject Object
        (
            [instance] => 3
        )

    [object2] => SubObject Object
        (
            [instance] => 2
        )

)


   

It is possible to access a member of a freshly cloned object in a single expression:

Access member of freshly cloned object

<?php
$dateTime = new DateTime();
echo (clone $dateTime)->format('Y');
?>

   

ENTITY

2016

Cloning with property overrides

As of PHP 8.5.0, clone is also available as a function, whose second parameter withProperties takes an array mapping property names to the values the copy receives. Only the listed properties are overridden, every other property keeps the value it was copied with.

The overrides are applied after __clone() has run, and they honour the visibility of all properties. Readonly properties can be updated on the copy even if they were already set on the original object, which makes the function suited to methods returning a modified copy.

Cloning an object with property overrides

<?php
class Point {
    public function __construct(
        public readonly int $x,
        public readonly int $y,
    ) {}

    public function withX(int $x): static
    {
        return clone($this, ['x' => $x]);
    }
}

$p = new Point(1, 2);
$q = $p->withX(10);

echo $q->x, ' ', $q->y;
?>

    

ENTITY

10 2

Class Constants

It is possible to define constants on a per-class basis. The default visibility of class constants is public.

[!NOTE] Class constants can be redefined by a child class. As of PHP 8.1.0, class constants cannot be redefined by a child class if it is defined as final.

It's also possible for interfaces to have constants. Look at the interface documentation for examples.

It's possible to reference the class using a variable. The variable's value can not be a keyword (e.g. self, parent and static).

Note that class constants are allocated once per class, and not for each class instance.

As of PHP 8.3.0, class constants can have a scalar type such as bool, int, float, string, or even array. When using array, the contents can only be other scalar types.

Defining and using a constant

<?php
class MyClass
{
    const CONSTANT = 'constant value';

    function showConstant() {
        echo  self::CONSTANT . "\n";
    }
}

echo MyClass::CONSTANT . "\n";

$classname = "MyClass";
echo $classname::CONSTANT . "\n";

$class = new MyClass();
$class->showConstant();

echo $class::CONSTANT."\n";
?>

  

The special ::class constant allows for fully qualified class name resolution at compile time, this is useful for namespaced classes:

Namespaced ::class example

<?php
namespace foo {
    class bar {
    }

    echo bar::class; // foo\bar
}
?>

  

Class constant expression example

<?php
const ONE = 1;
class foo {
    const TWO = ONE * 2;
    const THREE = ONE + self::TWO;
    const SENTENCE = 'The value of THREE is '.self::THREE;
}
?>

  

Class constant visibility modifiers, as of PHP 7.1.0

<?php
class Foo {
    public const BAR = 'bar';
    private const BAZ = 'baz';
}
echo Foo::BAR, PHP_EOL;
echo Foo::BAZ, PHP_EOL;
?>

  

ENTITY

bar

Fatal error: Uncaught Error: Cannot access private const Foo::BAZ in …

[!NOTE] As of PHP 7.1.0 visibility modifiers are allowed for class constants.

Class constant visibility variance check, as of PHP 8.3.0

<?php

interface MyInterface
{
    public const VALUE = 42;
}

class MyClass implements MyInterface
{
    protected const VALUE = 42;
}
?>

  

ENTITY

Fatal error: Access level to MyClass::VALUE must be public (as in interface MyInterface) …

[!NOTE] As of PHP 8.3.0 visibility variance is checked more strictly. Prior to this version, the visibility of a class constant could be different from the visibility of the constant in the implemented interface.

Fetch class constant syntax, as of PHP 8.3.0

<?php
class Foo {
    public const BAR = 'bar';
    private const BAZ = 'baz';
}

$name = 'BAR';
echo Foo::{$name}, PHP_EOL; // bar
?>

  

[!NOTE] As of PHP 8.3.0, class constants can be fetched dynamically using a variable.

Assigning types to class constants, as of PHP 8.3.0

<?php

class MyClass {
    public const bool MY_BOOL = true;
    public const int MY_INT = 1;
    public const float MY_FLOAT = 1.01;
    public const string MY_STRING = 'one';
    public const array MY_ARRAY = [self::MY_BOOL, self::MY_INT, self::MY_FLOAT, self::MY_STRING];
}

var_dump(MyClass::MY_BOOL);
var_dump(MyClass::MY_INT);
var_dump(MyClass::MY_FLOAT);
var_dump(MyClass::MY_STRING);
var_dump(MyClass::MY_ARRAY);
?>

  

ENTITY

bool(true)
int(1)
float(1.01)
string(3) "one"
array(4) {
  [0]=>
  bool(true)
  [1]=>
  int(1)
  [2]=>
  float(1.01)
  [3]=>
  string(3) "one"
}

Constructors and Destructors

Constructor

void

__construct

mixed

values

""

PHP allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.

[!NOTE] Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct within the child constructor is required. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).

Constructors in inheritance

<?php
class BaseClass {
    function __construct() {
        print "In BaseClass constructor\n";
    }
}

class SubClass extends BaseClass {
    function __construct() {
        parent::__construct();
        print "In SubClass constructor\n";
    }
}

class OtherSubClass extends BaseClass {
    // inherits BaseClass's constructor
}

// In BaseClass constructor
$obj = new BaseClass();

// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();

// In BaseClass constructor
$obj = new OtherSubClass();
?> 

    

Unlike other methods, __construct() is exempt from the usual signature compatibility rules when being extended.

Constructors are ordinary methods which are called during the instantiation of their corresponding object. As such, they may define an arbitrary number of arguments, which may be required, may have a type, and may have a default value. Constructor arguments are called by placing the arguments in parentheses after the class name.

Using constructor arguments

<?php
class Point {
    protected int $x;
    protected int $y;

    public function __construct(int $x, int $y = 0) {
        $this->x = $x;
        $this->y = $y;
    }
}

// Pass both parameters.
$p1 = new Point(4, 5);
// Pass only the required parameter. $y will take its default value of 0.
$p2 = new Point(4);
// With named parameters (as of PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>

    

If a class has no constructor, or the constructor has no required arguments, the parentheses may be omitted.

Old-style constructors

Prior to PHP 8.0.0, classes in the global namespace will interpret a method named the same as the class as an old-style constructor. That syntax is deprecated, and will result in an E_DEPRECATED error but still call that function as a constructor. If both __construct() and a same-name method are defined, __construct() will be called.

In namespaced classes, or any class as of PHP 8.0.0, a method named the same as the class never has any special meaning.

Always use __construct() in new code.

Constructor Promotion

As of PHP 8.0.0, constructor parameters may also be promoted to correspond to an object property. It is very common for constructor parameters to be assigned to a property in the constructor but otherwise not operated upon. Constructor promotion provides a short-hand for that use case. The example above could be rewritten as the following.

Using constructor property promotion

<?php
class Point {
    public function __construct(protected int $x, protected int $y = 0) {
    }
}

     

When a constructor argument includes a modifier, PHP will interpret it as both an object property and a constructor argument, and assign the argument value to the property. The constructor body may then be empty or may contain other statements. Any additional statements will be executed after the argument values have been assigned to the corresponding properties.

Not all arguments need to be promoted. It is possible to mix and match promoted and not-promoted arguments, in any order. Promoted arguments have no impact on code calling the constructor.

[!NOTE] Using a visibility modifier (public, protected or private) is the most likely way to apply property promotion, but any other single modifier (such as readonly) will have the same effect.

[!NOTE] Object properties may not be typed callable due to engine ambiguity that this would introduce. Promoted arguments, therefore, may not be typed callable either. Any other type declaration is permitted, however.

[!NOTE] As promoted properties are desugared to both a property as well as a function parameter, any and all naming restrictions for both properties as well as parameters apply.

[!NOTE] Attributes placed on a promoted constructor argument will be replicated to both the property and argument. Default values on a promoted constructor argument will be replicated only to the argument and not the property.

New in initializers

As of PHP 8.1.0, objects can be used as default parameter values, static variables, and global constants, as well as in attribute arguments. Objects can also be passed to define now.

[!NOTE] The use of a dynamic or non-string class name or an anonymous class is not allowed. The use of argument unpacking is not allowed. The use of unsupported expressions as arguments is not allowed.

Using new in initializers

<?php

// All allowed:
static $x = new Foo;

const C = new Foo;
 
function test($param = new Foo) {}
 
#[AnAttribute(new Foo)]
class Test {
    public function __construct(
        public $prop = new Foo,
    ) {}
}

// All not allowed (compile-time error):
function test(
    $a = new (CLASS_NAME_CONSTANT)(), // dynamic class name
    $b = new class {}, // anonymous class
    $c = new A(...[]), // argument unpacking
    $d = new B($abc), // unsupported constant expression
) {}
?>

     

Static creation methods

PHP only supports a single constructor per class. In some cases, however, it may be desirable to allow an object to be constructed in different ways with different inputs. The recommended way to do so is by using static methods as constructor wrappers.

Using static creation methods

<?php
$some_json_string = '{ "id": 1004, "name": "Elephpant" }';
$some_xml_string = "<animal><id>1005</id><name>Elephpant</name></animal>";

class Product {

    private ?int $id;
    private ?string $name;

    private function __construct(?int $id = null, ?string $name = null) {
        $this->id = $id;
        $this->name = $name;
    }

    public static function fromBasicData(int $id, string $name): static {
        $new = new static($id, $name);
        return $new;
    }

    public static function fromJson(string $json): static {
        $data = json_decode($json, true);
        return new static($data['id'], $data['name']);
    }

    public static function fromXml(string $xml): static {
        $data = simplexml_load_string($xml);
        $new = new static();
        $new->id = (int) $data->id;
        $new->name = $data->name;
        return $new;
    }
}

$p1 = Product::fromBasicData(5, 'Widget');
$p2 = Product::fromJson($some_json_string);
$p3 = Product::fromXml($some_xml_string);

var_dump($p1, $p2, $p3);

     

The constructor may be made private or protected to prevent it from being called externally. If so, only a static method will be able to instantiate the class. Because they are in the same class definition they have access to private methods, even if not of the same object instance. The private constructor is optional and may or may not make sense depending on the use case.

The three public static methods then demonstrate different ways of instantiating the object.

fromBasicData()

takes the exact parameters that are needed, then creates the object by calling the constructor and returning the result.

fromJson()

accepts a JSON string and does some pre-processing on it itself to convert it into the format desired by the constructor. It then returns the new object.

fromXml()

accepts an XML string, preprocesses it, and then creates a bare object. The constructor is still called, but as all of the parameters are optional the method skips them. It then assigns values to the object properties directly before returning the result.

In all three cases, the static keyword is translated into the name of the class the code is in. In this case, Product.

Destructor

void

__destruct

PHP possesses a destructor concept similar to that of other object-oriented languages, such as C++. The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.

Destructor Example

<?php

class MyDestructableClass 
{
    function __construct() {
        print "In constructor\n";
    }

    function __destruct() {
        print "Destroying " . __CLASS__ . "\n";
    }
}

$obj = new MyDestructableClass();
 

    

Like constructors, parent destructors will not be called implicitly by the engine. In order to run a parent destructor, one would have to explicitly call parent::__destruct in the destructor body. Also like constructors, a child class may inherit the parent's destructor if it does not implement one itself.

The destructor will be called even if script execution is stopped using exit. Calling exit in a destructor will prevent the remaining shutdown routines from executing.

If a destructor creates new references to its object, it will not be called a second time when the reference count reaches zero again or during the shutdown sequence.

As of PHP 8.4.0, when cycle collection occurs during the execution of a Fiber, the destructors of objects scheduled for collection are executed in a separate Fiber, called the gc_destructor_fiber. If this Fiber is suspended, a new one will be created to execute any remaining destructors. The previous gc_destructor_fiber will no longer be referenced by the garbage collector and may be collected if it is not referenced elsewhere. Objects whose destructor is suspended will not be collected until the destructor returns or the Fiber itself is collected.

[!NOTE] Destructors called during the script shutdown have HTTP headers already sent. The working directory in the script shutdown phase can be different with some SAPIs (e.g. Apache).

[!NOTE] Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error.

Final Keyword

The final keyword prevents child classes from overriding a method, property, or constant by prefixing the definition with final. If the class itself is being defined final then it cannot be extended.

Final methods example

<?php
class BaseClass {
   public function test() {
       echo "BaseClass::test() called\n";
   }
   
   final public function moreTesting() {
       echo "BaseClass::moreTesting() called\n";
   }
}

class ChildClass extends BaseClass {
   public function moreTesting() {
       echo "ChildClass::moreTesting() called\n";
   }
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?> 

   

Final class example

<?php
final class BaseClass {
   public function test() {
       echo "BaseClass::test() called\n";
   }

   // As the class is already final, the final keyword is redundant
   final public function moreTesting() {
       echo "BaseClass::moreTesting() called\n";
   }
}

class ChildClass extends BaseClass {
}
// Results in Fatal error: Class ChildClass may not inherit from final class (BaseClass)
?> 

   

Final property example as of PHP 8.4.0

<?php
class BaseClass {
   final protected string $test;
}

class ChildClass extends BaseClass {
    public string $test;
}
// Results in Fatal error: Cannot override final property BaseClass::$test
?>

  

Final constants example as of PHP 8.1.0

<?php
class Foo
{
    final public const X = "foo";
}

class Bar extends Foo
{
    public const X = "bar";
}

// Fatal error: Bar::X cannot override final constant Foo::X
?>

  

[!NOTE] As of PHP 8.0.0, private methods may not be declared final except for the constructor.

[!NOTE] A property that is declared private(set) is implicitly final.

Object Inheritance

Inheritance is a well-established programming principle, and PHP makes use of this principle in its object model. This principle will affect the way many classes and objects relate to one another.

For example, when extending a class, the subclass inherits all of the public and protected methods, properties and constants from the parent class. Unless a class overrides those methods, they will retain their original functionality.

This is useful for defining and abstracting functionality, and permits the implementation of additional functionality in similar objects without the need to reimplement all of the shared functionality.

Private methods of a parent class are not accessible to a child class. As a result, child classes may reimplement a private method themselves without regard for normal inheritance rules. Prior to PHP 8.0.0, however, final and static restrictions were applied to private methods. As of PHP 8.0.0, the only private method restriction that is enforced is private final constructors, as that is a common way to "disable" the constructor when using static factory methods instead.

The visibility of methods, properties and constants can be relaxed, e.g. a protected method can be marked as public, but they cannot be restricted, e.g. marking a public property as private. One exception is constructors, whose visibility can be restricted, e.g. a public constructor can be marked as private in a child class.

[!NOTE] Unless autoloading is used, the classes must be defined before they are used. If a class extends another, then the parent class must be declared before the child class structure. This rule applies to classes that inherit other classes and interfaces.

[!NOTE] It is not allowed to override a read-write property with a readonly property or vice versa.

<?php

class A {
    public int $prop;
}
class B extends A {
    // Illegal: read-write -> readonly
    public readonly int $prop;
}
?>

     

Inheritance Example

<?php

class Foo
{
    public function printItem($string)
    {
        echo 'Foo: ' . $string . PHP_EOL;
    }
    
    public function printPHP()
    {
        echo 'PHP is great.' . PHP_EOL;
    }
}

class Bar extends Foo
{
    public function printItem($string)
    {
        echo 'Bar: ' . $string . PHP_EOL;
    }
}

$foo = new Foo();
$bar = new Bar();
$foo->printItem('baz'); // Output: 'Foo: baz'
$foo->printPHP();       // Output: 'PHP is great.'
$bar->printItem('baz'); // Output: 'Bar: baz'
$bar->printPHP();       // Output: 'PHP is great.'

?>

  

Return Type Compatibility with Internal Classes

Prior to PHP 8.1, most internal classes or methods didn't declare their return types, and any return type was allowed when extending them.

As of PHP 8.1.0, most internal methods started to "tentatively" declare their return type, in that case the return type of methods should be compatible with the parent being extended; otherwise, a deprecation notice is emitted. Note that lack of an explicit return declaration is also considered a signature mismatch, and thus results in the deprecation notice.

If the return type cannot be declared for an overriding method due to PHP cross-version compatibility concerns, a ReturnTypeWillChange attribute can be added to silence the deprecation notice.

The overriding method does not declare any return type

<?php
class MyDateTime extends DateTime
{
    public function modify(string $modifier) { return false; }
}
 
// "Deprecated: Return type of MyDateTime::modify(string $modifier) should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" as of PHP 8.1.0
?> 

    

The overriding method declares a wrong return type

<?php
class MyDateTime extends DateTime
{
    public function modify(string $modifier): ?DateTime { return null; }
}
 
// "Deprecated: Return type of MyDateTime::modify(string $modifier): ?DateTime should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" as of PHP 8.1.0
?> 

    

The overriding method declares a wrong return type without a deprecation notice

<?php
class MyDateTime extends DateTime
{
    /**
     * @return DateTime|false
     */
    #[\ReturnTypeWillChange]
    public function modify(string $modifier) { return false; }
}
 
// No notice is triggered 
?> 

    

Object Interfaces

Object interfaces allow you to create code which specifies which methods and properties a class must implement, without having to define how these methods or properties are implemented. Interfaces share a namespace with classes, traits, and enumerations, so they may not use the same name.

Interfaces are defined in the same way as a class, but with the interface keyword replacing the class keyword and without any of the methods having their contents defined.

All methods declared in an interface must be public; this is the nature of an interface.

In practice, interfaces serve two complementary purposes:

To allow developers to create objects of different classes that may be used interchangeably because they implement the same interface or interfaces. A common example is multiple database access services, multiple payment gateways, or different caching strategies. Different implementations may be swapped out without requiring any changes to the code that uses them.

To allow a function or method to accept and operate on a parameter that conforms to an interface, while not caring what else the object may do or how it is implemented. These interfaces are often named like

Iterable

,

Cacheable

,

Renderable

, and so on to describe the significance of the behavior.

Interfaces may define magic methods to require implementing classes to implement those methods.

[!NOTE] Although they are supported, including constructors in interfaces is strongly discouraged. Doing so significantly reduces the flexibility of the object implementing the interface. Additionally, constructors are not enforced by inheritance rules, which can cause inconsistent and unexpected behavior.

implements

To implement an interface, the implements operator is used. All methods in the interface must be implemented within a class; failure to do so will result in a fatal error. Classes may implement more than one interface if desired by separating each interface with a comma.

[!WARNING] A class that implements an interface may use a different name for its parameters than the interface. However, as of PHP 8.0 the language supports named arguments, which means callers may rely on the parameter name in the interface. For that reason, it is strongly recommended that developers use the same parameter names as the interface being implemented.

[!NOTE] Interfaces can be extended like classes using the extends operator.

[!NOTE] The class implementing the interface must declare all methods in the interface with a compatible signature. A class can implement multiple interfaces which declare a method with the same name. In this case, the implementation must follow the signature compatibility rules for all the interfaces. So covariance and contravariance can be applied.

Constants

It's possible for interfaces to have constants. Interface constants work exactly like class constants. Prior to PHP 8.1.0, they cannot be overridden by a class/interface that inherits them.

Properties

As of PHP 8.4.0, interfaces may also declare properties. If they do, the declaration must specify if the property is to be readable, writeable, or both. The interface declaration applies only to public read and write access.

A class may satisfy an interface property in multiple ways. It may define a public property. It may define a public virtual property that implements only the corresponding hook. Or a read property may be satisfied by a readonly property. However, an interface property that is settable may not be readonly.

Interface properties example

<?php
interface I
{
    // An implementing class MUST have a publicly-readable property,
    // but whether or not it's publicly settable is unrestricted.
    public string $readable { get; }

    // An implementing class MUST have a publicly-writeable property,
    // but whether or not it's publicly readable is unrestricted.
    public string $writeable { set; }

    // An implementing class MUST have a property that is both publicly
    // readable and publicly writeable.
    public string $both { get; set; }
}

// This class implements all three properties as traditional, un-hooked
// properties. That's entirely valid.
class C1 implements I
{
    public string $readable;

    public string $writeable;

    public string $both;
}

// This class implements all three properties using just the hooks
// that are requested.  This is also entirely valid.
class C2 implements I
{
    private string $written = '';
    private string $all = '';

    // Uses only a get hook to create a virtual property.
    // This satisfies the "public get" requirement.
    // It is not writeable, but that is not required by the interface.
    public string $readable { get => strtoupper($this->writeable); }

    // The interface only requires the property be settable,
    // but also including get operations is entirely valid.
    // This example creates a virtual property, which is fine.
    public string $writeable {
        get => $this->written;
        set {
            $this->written = $value;
        }
    }

    // This property requires both read and write be possible,
    // so we need to either implement both, or allow it to have
    // the default behavior.
    public string $both {
        get => $this->all;
        set {
            $this->all = strtoupper($value);
        }
    }
}
?>

    

ENTITY

Interface example

<?php

// Declare the interface 'Template'
interface Template
{
    public function setVariable($name, $var);
    public function getHtml($template);
}

// Implement the interface
// This will work
class WorkingTemplate implements Template
{
    private $vars = [];
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
  
    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }
 
        return $template;
    }
}

// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (Template::getHtml)
class BadTemplate implements Template
{
    private $vars = [];
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
}
?>

    

Extendable Interfaces

<?php
interface A
{
    public function foo();
}

interface B extends A
{
    public function baz(Baz $baz);
}

// This will work
class C implements B
{
    public function foo()
    {
    }

    public function baz(Baz $baz)
    {
    }
}

// This will not work and result in a fatal error
class D implements B
{
    public function foo()
    {
    }

    public function baz(Foo $foo)
    {
    }
}
?>

     

Variance compatibility with multiple interfaces

<?php
class Foo {}
class Bar extends Foo {}

interface A {
    public function myfunc(Foo $arg): Foo;
}

interface B {
    public function myfunc(Bar $arg): Bar;
}

class MyClass implements A, B
{
    public function myfunc(Foo $arg): Bar
    {
        return new Bar();
    }
}
?>

     

Multiple interface inheritance

<?php
interface A
{
    public function foo();
}

interface B
{
    public function bar();
}

interface C extends A, B
{
    public function baz();
}

class D implements C
{
    public function foo()
    {
    }

    public function bar()
    {
    }

    public function baz()
    {
    }
}
?>

     

Interfaces with constants

<?php
interface A
{
    const B = 'Interface constant';
}

// Prints: Interface constant
echo A::B;


class B implements A
{
    const B = 'Class constant';
}

// Prints: Class constant
// Prior to PHP 8.1.0, this will however not work because it was not
// allowed to override constants.
echo B::B;
?>

     

Interfaces with abstract classes

<?php
interface A
{
    public function foo(string $s): string;

    public function bar(int $i): int;
}

// An abstract class may implement only a portion of an interface.
// Classes that extend the abstract class must implement the rest.
abstract class B implements A
{
    public function foo(string $s): string
    {
        return $s . PHP_EOL;
    }
}

class C extends B
{
    public function bar(int $i): int
    {
        return $i * 2;
    }
}
?>

     

Extending and implementing simultaneously

<?php

class One
{
    /* ... */
}

interface Usable
{
    /* ... */
}

interface Updatable
{
    /* ... */
}

// The keyword order here is important. 'extends' must come first.
class Two extends One implements Usable, Updatable
{
    /* ... */
}
?>

     

An interface, together with type declarations, provides a good way to make sure that a particular object contains particular methods. See instanceof operator and type declarations.

Object Iteration

PHP provides a way for objects to be defined so it is possible to iterate through a list of items with, for example, a ENTITY statement. By default, all visible properties will be used for the iteration.

Simple Object Iteration

<?php
class MyClass
{
    public $var1 = 'value 1';
    public $var2 = 'value 2';
    public $var3 = 'value 3';

    protected $protected = 'protected var';
    private   $private   = 'private var';

    function iterateVisible() {
       echo "MyClass::iterateVisible:\n";
       foreach ($this as $key => $value) {
           print "$key => $value\n";
       }
    }
}

$class = new MyClass();

foreach($class as $key => $value) {
    print "$key => $value\n";
}
echo "\n";


$class->iterateVisible();

?>

   

ENTITY

var1 => value 1
var2 => value 2
var3 => value 3

MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var

   

As the output shows, the ENTITY iterated through all of the visible properties that could be accessed.

ENTITY

Generators, Iterator, IteratorAggregate, SPL Iterators

Late Static Bindings

PHP implements a feature called late static bindings which can be used to reference the called class in the context of static inheritance.

More precisely, late static bindings work by storing the class named in the last "non-forwarding call". In case of static method calls, this is the class explicitly named (usually the one on the left of the :: operator); in case of non static method calls, it is the class of the object. A "forwarding call" is a static one that is introduced by self::, parent::, static::, or, if going up in the class hierarchy, forward_static_call. The function get_called_class can be used to retrieve a string with the name of the called class and static:: introduces its scope.

This feature was named "late static bindings" with an internal perspective in mind. "Late binding" comes from the fact that static:: will not be resolved using the class where the method is defined but it will rather be computed using runtime information. It was also called a "static binding" as it can be used for (but is not limited to) static method calls.

Limitations of self::

Static references to the current class like self:: or __CLASS__ are resolved using the class in which the function belongs, as in where it was defined:

self:: usage

<?php

class A
{
    public static function who()
    {
        echo __CLASS__;
    }

    public static function test()
    {
        self::who();
    }
}

class B extends A
{
    public static function who()
    {
        echo __CLASS__;
    }
}

B::test();

?>

    

ENTITY

A

Late Static Bindings' usage

Late static bindings tries to solve that limitation by introducing a keyword that references the class that was initially called at runtime. Basically, a keyword that would allow referencing B from test() in the previous example. It was decided not to introduce a new keyword but rather use static that was already reserved.

static:: simple usage

<?php

class A
{
    public static function who()
    {
        echo __CLASS__;
    }

    public static function test()
    {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A
{
    public static function who()
    {
        echo __CLASS__;
    }
}

B::test();

?>

    

ENTITY

B

[!NOTE] In non-static contexts, the called class will be the class of the object instance. Since $this-> will try to call private methods from the same scope, using static:: may give different results. Another difference is that static:: can only refer to static properties.

static:: usage in a non-static context

<?php

class A
{
    private function foo()
    {
        echo "Success!\n";
    }

    public function test()
    {
        $this->foo();
        static::foo();
    }
}

class B extends A
{
    /* foo() will be copied to B, hence its scope will still be A and
    * the call be successful */
}

class C extends A
{
    private function foo()
    {
        /* Original method is replaced; the scope of the new one is C */
    }
}

$b = new B();
$b->test();

$c = new C();
try {
    $c->test();
} catch (Error $e) {
    echo $e->getMessage();
}

?>

    

ENTITY

Success!
Success!
Success!
Call to private method C::foo() from scope A

[!NOTE] Late static bindings' resolution will stop at a fully resolved static call with no fallback. On the other hand, static calls using keywords like parent:: or self:: will forward the calling information.

Forwarding and non-forwarding calls

<?php

class A
{
    public static function foo()
    {
        static::who();
    }

    public static function who()
    {
        echo __CLASS__ . "\n";
    }
}

class B extends A
{
    public static function test()
    {
        A::foo();
        parent::foo();
        self::foo();
    }

    public static function who()
    {
        echo __CLASS__ . "\n";
    }
}

class C extends B
{
    public static function who()
    {
        echo __CLASS__ . "\n";
    }
}

C::test();

?>

     

ENTITY

A
C
C

Lazy Objects

A lazy object is an object whose initialization is deferred until its state is observed or modified. Some use-case examples include dependency injection components that provide lazy services fully initialized only if needed, ORMs providing lazy entities that hydrate themselves from the database only when accessed, or a JSON parser that delays parsing until elements are accessed.

Two lazy object strategies are supported: Ghost Objects and Virtual Proxies, hereafter referred to as ENTITYlazy ghostsENTITY and ENTITYlazy proxiesENTITY. In both strategies, the lazy object is attached to an initializer or factory that is called automatically when its state is observed or modified for the first time. From an abstraction point of view, lazy ghost objects are indistinguishable from non-lazy ones: they can be used without knowing they are lazy, allowing them to be passed to and used by code that is unaware of laziness. Lazy proxies are similarly transparent, but care must be taken when their identity is used, as the proxy and its real instance have different identities.

[!NOTE] Lazy objects were introduced in PHP 8.4.

Creating Lazy Objects

It is possible to create a lazy instance of any user defined class or the stdClass class (other internal classes are not supported), or to reset an instance of these classes to make it lazy. The entry points for creating a lazy object are the ReflectionClass::newLazyGhost and ReflectionClass::newLazyProxy methods.

Both methods accept a function that is called when the object requires initialization. The function's expected behavior varies depending on the strategy in use, as described in the reference documentation for each method.

Creating a Lazy Ghost

<?php
class Example
{
    public function __construct(public int $prop)
    {
        echo __METHOD__, "\n";
    }
}

$reflector = new ReflectionClass(Example::class);
$lazyObject = $reflector->newLazyGhost(function (Example $object) {
    // Initialize object in-place
    $object->__construct(1);
});

var_dump($lazyObject);
var_dump(get_class($lazyObject));

// Triggers initialization
var_dump($lazyObject->prop);
?>

   

ENTITY

lazy ghost object(Example)#3 (0) {
  ["prop"]=>
  uninitialized(int)
}
string(7) "Example"
Example::__construct
int(1)

Creating a Lazy Proxy

<?php
class Example
{
    public function __construct(public int $prop)
    {
        echo __METHOD__, "\n";
    }
}

$reflector = new ReflectionClass(Example::class);
$lazyObject = $reflector->newLazyProxy(function (Example $object) {
    // Create and return the real instance
    return new Example(1);
});

var_dump($lazyObject);
var_dump(get_class($lazyObject));

// Triggers initialization
var_dump($lazyObject->prop);
?>

   

ENTITY

lazy proxy object(Example)#3 (0) {
  ["prop"]=>
  uninitialized(int)
}
string(7) "Example"
Example::__construct
int(1)

Any access to properties of a lazy object triggers its initialization (including via ReflectionProperty). However, certain properties might be known in advance and should not trigger initialization when accessed:

Initializing Properties Eagerly

<?php
class BlogPost
{
    public function __construct(
        public int $id,
        public string $title,
        public string $content,
    ) { }
}

$reflector = new ReflectionClass(BlogPost::class);

$post = $reflector->newLazyGhost(function ($post) {
    $data = fetch_from_store($post->id);
    $post->__construct($data['id'], $data['title'], $data['content']);
});

// Without this line, the following call to ReflectionProperty::setValue() would
// trigger initialization.
$reflector->getProperty('id')->skipLazyInitialization($post);
$reflector->getProperty('id')->setValue($post, 123);

// Alternatively, one can use this directly:
$reflector->getProperty('id')->setRawValueWithoutLazyInitialization($post, 123);

// The id property can be accessed without triggering initialization
var_dump($post->id);
?>

   

The ReflectionProperty::skipLazyInitialization and ReflectionProperty::setRawValueWithoutLazyInitialization methods offer ways to bypass lazy-initialization when accessing a property.

About Lazy Object Strategies

Lazy ghosts are objects that initialize in-place and, once initialized, are indistinguishable from an object that was never lazy. This strategy is suitable when we control both the instantiation and initialization of the object, making it unsuitable if either of these is managed by another party.

Lazy proxies, once initialized, act as proxies to a real instance: any operation on an initialized lazy proxy is forwarded to the real instance. The creation of the real instance can be delegated to another party, making this strategy useful in cases where lazy ghosts are unsuitable. Although lazy proxies are nearly as transparent as lazy ghosts, caution is needed when their identity is used, as the proxy and its real instance have distinct identities.

Lifecycle of Lazy Objects

Objects can be made lazy at instantiation time using ReflectionClass::newLazyGhost or ReflectionClass::newLazyProxy, or after instantiation by using ReflectionClass::resetAsLazyGhost or ReflectionClass::resetAsLazyProxy. Following this, a lazy object can become initialized through one of the following operations:

Interacting with the object in a way that triggers automatic initialization. See

Initialization triggers

.

Marking all its properties as non-lazy using

ReflectionProperty::skipLazyInitialization

or

ReflectionProperty::setRawValueWithoutLazyInitialization

.

Calling explicitly

ReflectionClass::initializeLazyObject

or

ReflectionClass::markLazyObjectAsInitialized

.

As lazy objects become initialized when all their properties are marked non-lazy, the above methods will not mark an object as lazy if no properties could be marked as lazy.

Initialization Triggers

Lazy objects are designed to be fully transparent to their consumers, so normal operations that observe or modify the object's state will automatically trigger initialization before the operation is performed. This includes, but is not limited to, the following operations:

Reading or writing a property.

Testing if a property is set or unsetting it.

Accessing or modifying a property via

ReflectionProperty::getValue

,

ReflectionProperty::getRawValue

,

ReflectionProperty::setValue

, or

ReflectionProperty::setRawValue

.

Listing properties with

ReflectionObject::getProperties

,

ReflectionObject::getProperty

,

get_object_vars

.

Iterating over properties of an object that does not implement

Iterator

or

IteratorAggregate

using

foreach

.

Serializing the object with

serialize

,

json_encode

, etc.

Cloning

the object.

Method calls that do not access the object state will not trigger initialization. Similarly, interactions with the object that invoke magic methods or hook functions will not trigger initialization if these methods or functions do not access the object's state.

Non-Triggering Operations

The following specific methods or low-level operations allow access or modification of lazy objects without triggering initialization:

Marking properties as non-lazy with

ReflectionProperty::skipLazyInitialization

or

ReflectionProperty::setRawValueWithoutLazyInitialization

.

Retrieving the internal representation of properties using

get_mangled_object_vars

or by

casting the object to an array

.

Using

serialize

when

ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE

is set, unless

__serialize()

or

__sleep()

trigger initialization.

Calling

ReflectionObject::__toString

.

Using

var_dump

or

debug_zval_dump

, unless

__debugInfo()

triggers initialization.

Initialization Sequence

This section outlines the sequence of operations performed when initialization is triggered, based on the strategy in use.

Ghost Objects

The object is marked as non-lazy.

Properties not initialized with

ReflectionProperty::skipLazyInitialization

or

ReflectionProperty::setRawValueWithoutLazyInitialization

are set to their default values, if any. At this stage, the object resembles one created with

ReflectionClass::newInstanceWithoutConstructor

, except for already initialized properties.

The initializer function is then called with the object as its first parameter. The function is expected, but not required, to initialize the object state, and must return ENTITY or no value. The object is no longer lazy at this point, so the function can access its properties directly.

After initialization, the object is indistinguishable from an object that was never lazy.

Proxy Objects

The object is marked as non-lazy.

Unlike ghost objects, the properties of the object are not modified at this stage.

The factory function is called with the object as its first parameter and must return a non-lazy instance of a compatible class (see

ReflectionClass::newLazyProxy

).

The returned instance is referred to as the

real instance

and is attached to the proxy.

The proxy's property values are discarded as though

unset

was called.

After initialization, accessing any property on the proxy will yield the same result as accessing the corresponding property on the real instance; all property accesses on the proxy are forwarded to the real instance, including declared, dynamic, non-existing, or properties marked with ReflectionProperty::skipLazyInitialization or ReflectionProperty::setRawValueWithoutLazyInitialization.

The proxy object itself is not replaced or substituted for the real instance.

While the factory receives the proxy as its first parameter, it is not expected to modify it (modifications are allowed but will be lost during the final initialization step). However, the proxy can be used for decisions based on the values of initialized properties, the class, the object itself, or its identity. For instance, the initializer might use an initialized property's value when creating the real instance.

Common Behavior

The scope and $this context of the initializer or factory function remains unchanged, and usual visibility constraints apply.

After successful initialization, the initializer or factory function is no longer referenced by the object and may be released if it has no other references.

If the initializer throws an exception, the object state is reverted to its pre-initialization state and the object is marked as lazy again. In other words, all effects on the object itself are reverted. Other side effects, such as effects on other objects, are not reverted. This prevents exposing a partially initialized instance in case of failure.

Cloning

Cloning a lazy object triggers its initialization before the clone is created, resulting in an initialized object.

For proxy objects, both the proxy and its real instance are cloned, and the clone of the proxy is returned. The __clone method is called on the real instance, not on the proxy. The cloned proxy and real instance are linked as they are during initialization, so accesses to the proxy clone are forwarded to the real instance clone.

This behavior ensures that the clone and the original object maintain separate states. Changes to the original object or its initializer's state after cloning do not affect the clone. Cloning both the proxy and its real instance, rather than returning a clone of the real instance alone, ensures that the clone operation consistently returns an object of the same class.

Destructors

For lazy ghosts, the destructor is only called if the object has been initialized. For proxies, the destructor is only called on the real instance, if one exists.

The ReflectionClass::resetAsLazyGhost and ReflectionClass::resetAsLazyProxy methods may invoke the destructor of the object being reset.

Magic Methods

Magic methods are special methods which override PHP's default action when certain actions are performed on an object.

[!CAUTION] All method names starting with __ are reserved by PHP. Therefore, it is not recommended to use such method names unless overriding PHP's behavior.

The following method names are considered magical: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __serialize(), __unserialize(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone(), and __debugInfo().

[!WARNING] All magic methods, with the exception of __construct(), __destruct(), and __clone(), must be declared as public, otherwise an E_WARNING is emitted. Prior to PHP 8.0.0, no diagnostic was emitted for the magic methods __sleep(), __wakeup(), __serialize(), __unserialize(), and __set_state().

[!WARNING] If type declarations are used in the definition of a magic method, they must be identical to the signature described in this document. Otherwise, a fatal error is emitted. Prior to PHP 8.0.0, no diagnostic was emitted. However, __construct() and __destruct() must not declare a return type; otherwise a fatal error is emitted.

__serialize() and __unserialize()

public

array

__serialize

public

void

__unserialize

array

data

serialize checks if the class has a function with the magic name __serialize(). If so, that function is executed prior to any serialization. It must construct and return an associative array of key/value pairs that represent the serialized form of the object. If no array is returned a TypeError will be thrown.

[!NOTE] If both __serialize() and __sleep() are defined in the same object, only __serialize() will be called. __sleep() will be ignored. If the object implements the Serializable interface, the interface's serialize() method will be ignored and __serialize() used instead.

The intended use of __serialize() is to define a serialization-friendly arbitrary representation of the object. Elements of the array may correspond to properties of the object but that is not required.

Conversely, unserialize checks for the presence of a function with the magic name __unserialize(). If present, this function will be passed the restored array that was returned from __serialize(). It may then restore the properties of the object from that array as appropriate.

[!NOTE] If both __unserialize() and __wakeup() are defined in the same object, only __unserialize() will be called. __wakeup() will be ignored.

[!NOTE] This feature is available as of PHP 7.4.0.

Serialize and unserialize

<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;

    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }

    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }

    public function __serialize(): array
    {
        return [
          'dsn' => $this->dsn,
          'user' => $this->username,
          'pass' => $this->password,
        ];
    }

    public function __unserialize(array $data): void
    {
        $this->dsn = $data['dsn'];
        $this->username = $data['user'];
        $this->password = $data['pass'];

        $this->connect();
    }
}?>

    

__sleep() and __wakeup()

[!WARNING] This serialization mechanism is soft-deprecated as of PHP 8.5.0. It is maintained for backward compatibility. However, new and existing code should be migrated to use the __serialize() and __unserialize() magic methods instead.

public

array

__sleep

public

void

__wakeup

serialize checks if the class has a function with the magic name __sleep(). If so, that function is executed prior to any serialization. It can clean up the object and is supposed to return an array with the names of all variables of that object that should be serialized. If the method doesn't return anything then ENTITY is serialized and E_NOTICE is issued.

[!NOTE] It is not possible for __sleep() to return names of private properties in parent classes. Doing this will result in an E_NOTICE level error. Use __serialize() instead.

[!NOTE] As of PHP 8.0.0, returning a value which is not an array from __sleep() generates a warning. Previously, it generated a notice.

The intended use of __sleep() is to commit pending data or perform similar cleanup tasks. Also, the function is useful if a very large object doesn't need to be saved completely.

Conversely, unserialize checks for the presence of a function with the magic name __wakeup(). If present, this function can reconstruct any resources that the object may have.

The intended use of __wakeup() is to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks.

Sleep and wakeup

<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;

    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }

    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }

    public function __sleep()
    {
        return array('dsn', 'username', 'password');
    }

    public function __wakeup()
    {
        $this->connect();
    }
}?>

   

__toString()

public

string

__toString

The __toString() method allows a class to decide how it will react when it is treated like a string. For example, what echo $obj; will print.

[!WARNING] As of PHP 8.0.0, the return value follows standard PHP type semantics, meaning it will be coerced into a string if possible and if strict typing is disabled.

A Stringable object will not be accepted by a string type declaration if strict typing is enabled. If such behaviour is wanted the type declaration must accept Stringable and string via a union type.

As of PHP 8.0.0, any class that contains a __toString() method will also implicitly implement the Stringable interface, and will thus pass type checks for that interface. Explicitly implementing the interface anyway is recommended.

In PHP 7.4, the returned value must be a string, otherwise an Error is thrown.

Prior to PHP 7.4.0, the returned value must be a string, otherwise a fatal E_RECOVERABLE_ERROR is emitted.

[!WARNING] It was not possible to throw an exception from within a __toString() method prior to PHP 7.4.0. Doing so will result in a fatal error.

Simple example

<?php
// Declare a simple class
class TestClass
{
    public $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        return $this->foo;
    }
}

$class = new TestClass('Hello');
echo $class;
?>

    

ENTITY

Hello

__invoke()

mixed

__invoke

values

The __invoke() method is called when a script tries to call an object as a function.

Using __invoke()

<?php
class CallableClass
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>

    

ENTITY

int(5)
bool(true)

Using __invoke()

<?php
class Sort
{
    private $key;

    public function __construct(string $key)
    {
        $this->key = $key;
    }

    public function __invoke(array $a, array $b): int
    {
        return $a[$this->key] <=> $b[$this->key];
    }
}

$customers = [
    ['id' => 1, 'first_name' => 'John', 'last_name' => 'Do'],
    ['id' => 3, 'first_name' => 'Alice', 'last_name' => 'Gustav'],
    ['id' => 2, 'first_name' => 'Bob', 'last_name' => 'Filipe']
];

// sort customers by first name
usort($customers, new Sort('first_name'));
print_r($customers);

// sort customers by last name
usort($customers, new Sort('last_name'));
print_r($customers);
?>

    

ENTITY

Array
(
    [0] => Array
        (
            [id] => 3
            [first_name] => Alice
            [last_name] => Gustav
        )

    [1] => Array
        (
            [id] => 2
            [first_name] => Bob
            [last_name] => Filipe
        )

    [2] => Array
        (
            [id] => 1
            [first_name] => John
            [last_name] => Do
        )

)
Array
(
    [0] => Array
        (
            [id] => 1
            [first_name] => John
            [last_name] => Do
        )

    [1] => Array
        (
            [id] => 2
            [first_name] => Bob
            [last_name] => Filipe
        )

    [2] => Array
        (
            [id] => 3
            [first_name] => Alice
            [last_name] => Gustav
        )

)

__set_state()

static

object

__set_state

array

properties

This static method is called for classes exported by var_export.

The only parameter of this method is an array containing exported properties in the form ['property' => value, ...].

<?php

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array)
    {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

$b = var_export($a, true);
var_dump($b);
eval('$c = ' . $b . ';');
var_dump($c);
?>

    

ENTITY

string(60) "A::__set_state(array(
   'var1' => 5,
   'var2' => 'foo',
))"
object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}

[!NOTE] When exporting an object, var_export does not check whether __set_state() is implemented by the object's class, so re-importing objects will result in an Error exception, if __set_state() is not implemented. Particularly, this affects some internal classes.

It is the responsibility of the programmer to verify that only objects whose class implements __set_state will be re-imported.

__debugInfo()

array

__debugInfo

This method is called by var_dump when dumping an object to get the properties that should be shown. If the method isn't defined on an object, then all public, protected and private properties will be shown.

As of PHP 8.5.0, returning ENTITY from __debugInfo() is deprecated. Return an empty array instead.

<?php
class C {
    private $prop;

    public function __construct($val) {
        $this->prop = $val;
    }

    public function __debugInfo() {
        return [
            'propSquared' => $this->prop ** 2,
        ];
    }
}

var_dump(new C(42));
?>

    

ENTITY

object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}

Comparing Objects

When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with ==), and are instances of the same class.

When using the identity operator (===), object variables are identical if and only if they refer to the same instance of the same class.

An example will clarify these rules.

Example of object comparison

<?php
function bool2str($bool)
{
    if ($bool === false) {
        return 'FALSE';
    } else {
        return 'TRUE';
    }
}

function compareObjects($o1, $o2)
{
    echo 'o1 == o2 : ' . bool2str($o1 == $o2) . "\n";
    echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";
    echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";
    echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";
}

class Flag
{
    public $flag;

    function __construct($flag = true) {
        $this->flag = $flag;
    }
}

class OtherFlag
{
    public $flag;

    function __construct($flag = true) {
        $this->flag = $flag;
    }
}

$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();

echo "Two instances of the same class\n";
compareObjects($o, $p);

echo "\nTwo references to the same instance\n";
compareObjects($o, $q);

echo "\nInstances of two different classes\n";
compareObjects($o, $r);
?>

     

ENTITY

Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE

[!NOTE] Extensions can define their own rules for comparing their objects (==).

Overloading

Overloading in PHP provides means to dynamically “create” properties and methods. These dynamic entities are processed via magic methods one can establish in a class for various action types.

The overloading methods are invoked when interacting with properties or methods that have not been declared or are not visible in the current scope. The rest of this section will use the terms “inaccessible properties” and “inaccessible methods” to refer to this combination of declaration and visibility.

All overloading methods must be defined as public.

[!NOTE] None of the arguments of these magic methods can be passed by reference.

[!NOTE] PHP's interpretation of “overloading” is different than most object-oriented languages. Overloading traditionally provides the ability to have multiple methods with the same name but different quantities and types of arguments.

Property overloading

public

void

__set

string

name

mixed

value

public

mixed

__get

string

name

public

bool

__isset

string

name

public

void

__unset

string

name

__set() is run when writing data to inaccessible (protected or private) or non-existing properties.

__get() is utilized for reading data from inaccessible (protected or private) or non-existing properties.

__isset() is triggered by calling isset or empty on inaccessible (protected or private) or non-existing properties.

__unset() is invoked when unset is used on inaccessible (protected or private) or non-existing properties.

The $name argument is the name of the property being interacted with. The __set() method's $value argument specifies the value the $name'ed property should be set to.

Property overloading only works in object context. These magic methods will not be triggered in static context. Therefore these methods should not be declared static. A warning is issued if one of the magic overloading methods is declared static.

[!NOTE] The return value of __set() is ignored because of the way PHP processes the assignment operator. Similarly, __get() is never called when chaining assignments together like this: $a = $obj->b = 8;

[!NOTE] PHP will not call an overloaded method from within the same overloaded method. That means, for example, writing return $this->foo inside of __get() will return ENTITY and raise an E_WARNING if there is no foo property defined, rather than calling __get() a second time. However, overload methods may invoke other overload methods implicitly (such as __set() triggering __get()).

Overloading properties via the __get(), __set(), __isset() and __unset() methods

<?php
class PropertyTest
{
    /**  Location for overloaded data.  */
    private $data = array();

    /**  Overloading not used on declared properties.  */
    public $declared = 1;

    /**  Overloading only used on this when accessed outside the class.  */
    private $hidden = 2;

    public function __set($name, $value)
    {
        echo "Setting '$name' to '$value'\n";
        $this->data[$name] = $value;
    }

    public function __get($name)
    {
        echo "Getting '$name'\n";
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        $trace = debug_backtrace();
        trigger_error(
            'Undefined property via __get(): ' . $name .
            ' in ' . $trace[0]['file'] .
            ' on line ' . $trace[0]['line'],
            E_USER_NOTICE);
        return null;
    }

    public function __isset($name)
    {
        echo "Is '$name' set?\n";
        return isset($this->data[$name]);
    }

    public function __unset($name)
    {
        echo "Unsetting '$name'\n";
        unset($this->data[$name]);
    }

    /**  Not a magic method, just here for example.  */
    public function getHidden()
    {
        return $this->hidden;
    }
}


$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "\n\n";

var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";

echo $obj->declared . "\n\n";

echo "Let's experiment with the private property named 'hidden':\n";
echo "Privates are visible inside the class, so __get() not used...\n";
echo $obj->getHidden() . "\n";
echo "Privates not visible outside of class, so __get() is used...\n";
echo $obj->hidden . "\n";
?>

    

ENTITY

Setting 'a' to '1'
Getting 'a'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'

Notice: Undefined property via __get(): hidden in script on line 71 in script on line 27

    

Method overloading

public

mixed

__call

string

name

array

arguments

public static

mixed

__callStatic

string

name

array

arguments

__call() is triggered when invoking inaccessible methods in an object context.

__callStatic() is triggered when invoking inaccessible methods in a static context.

The $name argument is the name of the method being called. The $arguments argument is an enumerated array containing the parameters passed to the $name'ed method.

Overloading methods via the __call() and __callStatic() methods

  
<?php
class MethodTest
{
    public function __call($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    public static function __callStatic($name, $arguments)
    {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');
?>

    

ENTITY

Calling object method 'runTest' in object context
Calling static method 'runTest' in static context

    

Scope Resolution Operator (::)

The Scope Resolution Operator (also called Paamayim Nekudotayim) or in simpler terms, the double colon, is a token that allows access to a constant, static property, or static method of a class or one of its parents. Moreover, static properties or methods can be overridden via late static binding.

When referencing these items from outside the class definition, use the name of the class.

It's possible to reference the class using a variable. The variable's value can not be a keyword (e.g. self, parent and static).

Paamayim Nekudotayim would, at first, seem like a strange choice for naming a double-colon. However, while writing the Zend Engine 0.5 (which powers PHP 3), that's what the Zend team decided to call it. It actually does mean double-colon - in Hebrew!

:: from outside the class definition

<?php
class MyClass {
    const CONST_VALUE = 'A constant value';
}

$classname = 'MyClass';
echo $classname::CONST_VALUE;

echo MyClass::CONST_VALUE;
?>

  

Three special keywords self, parent and static are used to access properties or methods from inside the class definition.

:: from inside the class definition

<?php
class MyClass {
    const CONST_VALUE = 'A constant value';
}

class OtherClass extends MyClass
{
    public static $my_static = 'static var';

    public static function doubleColon() {
        echo parent::CONST_VALUE . "\n";
        echo self::$my_static . "\n";
    }
}

$classname = 'OtherClass';
$classname::doubleColon();

OtherClass::doubleColon();
?>

  

When an extending class overrides the parent's definition of a method, PHP will not call the parent's method. It's up to the extended class whether or not the parent's method is called. This also applies to Constructors and Destructors, Overloading, and Magic method definitions.

Calling a parent's method

<?php
class MyClass
{
    protected function myFunc() {
        echo "MyClass::myFunc()\n";
    }
}

class OtherClass extends MyClass
{
    // Override parent's definition
    public function myFunc()
    {
        // But still call the parent function
        parent::myFunc();
        echo "OtherClass::myFunc()\n";
    }
}

$class = new OtherClass();
$class->myFunc();
?>

  

See also some examples of static call trickery.

Properties

Class member variables are called properties. They may be referred to using other terms such as fields, but for the purposes of this reference properties will be used. They are defined by using at least one modifier (such as ???, ???, or, as of PHP 8.1.0, readonly), optionally (except for readonly properties), as of PHP 7.4, followed by a type declaration, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value.

[!NOTE] An obsolete way of declaring class properties is by using the var keyword instead of a modifier.

[!NOTE] A property declared without a ??? modifier will be declared as public.

Within class methods non-static properties may be accessed by using -ENTITY (Object Operator): $this-ENTITYproperty (where property is the name of the property). Static properties are accessed by using the :: (Double Colon): self::$property. See ??? for more information on the difference between static and non-static properties.

The pseudo-variable $this is available inside any class method when that method is called from within an object context. $this is the value of the calling object.

Property declarations

<?php
class SimpleClass
{
   public $var1 = 'hello ' . 'world';
   public $var2 = <<<EOD
hello world
EOD;
   public $var3 = 1+2;
   // invalid property declarations:
   public $var4 = self::myStaticMethod();
   public $var5 = $myVar;

   // valid property declarations:
   public $var6 = myConstant;
   public $var7 = [true, false];

   public $var8 = <<<'EOD'
hello world
EOD;

   // Without visibility modifier:
   static $var9;
   readonly int $var10;
}
?>

    

[!NOTE] There are various functions to handle classes and objects. See the Class/Object Functions reference.

Type declarations

As of PHP 7.4.0, property definitions can include ???, with the exception of callable.

Example of typed properties

<?php

class User
{
    public int $id;
    public ?string $name;

    public function __construct(int $id, ?string $name)
    {
        $this->id = $id;
        $this->name = $name;
    }
}

$user = new User(1234, null);

var_dump($user->id);
var_dump($user->name);

?>

     

ENTITY

int(1234)
NULL

Typed properties must be initialized before accessing, otherwise an Error is thrown.

Accessing properties

<?php

class Shape
{
    public int $numberOfSides;
    public string $name;

    public function setNumberOfSides(int $numberOfSides): void
    {
        $this->numberOfSides = $numberOfSides;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }

    public function getNumberOfSides(): int
    {
        return $this->numberOfSides;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

$triangle = new Shape();
$triangle->setName("triangle");
$triangle->setNumberOfSides(3);
var_dump($triangle->getName());
var_dump($triangle->getNumberOfSides());

$circle = new Shape();
$circle->setName("circle");
var_dump($circle->getName());
var_dump($circle->getNumberOfSides());
?>

     

ENTITY

string(8) "triangle"
int(3)
string(6) "circle"

Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be accessed before initialization

Readonly properties

As of PHP 8.1.0, a property can be declared with the readonly modifier, which prevents modification of the property after initialization. Prior to PHP 8.4.0 a readonly property is implicitly private-set, and may only be written to from the same class. As of PHP 8.4.0, readonly properties are implicitly protected(set), so may be set from child classes. That may be overridden explicitly if desired.

Example of readonly properties

<?php

class Test {
   public readonly string $prop;

   public function __construct(string $prop) {
       // Legal initialization.
       $this->prop = $prop;
   }
}

$test = new Test("foobar");
// Legal read.
var_dump($test->prop); // string(6) "foobar"

// Illegal reassignment. It does not matter that the assigned value is the same.
$test->prop = "foobar";
// Error: Cannot modify readonly property Test::$prop
?>

     

[!NOTE] The readonly modifier can only be applied to typed properties. A readonly property without type constraints can be created using the ??? type.

[!NOTE] Readonly static properties are not supported.

A readonly property can only be initialized once, and only from the scope where it has been declared. Any other assignment or modification of the property will result in an Error exception.

Illegal initialization of readonly properties

<?php
class Test1 {
    public readonly string $prop;
}

$test1 = new Test1;
// Illegal initialization outside of private scope.
$test1->prop = "foobar";
// Error: Cannot initialize readonly property Test1::$prop from global scope
?>

     

[!NOTE] Readonly properties can only be initialized by a direct assignment. An uninitialized readonly property cannot be initialized by reference, not even from the scope where it has been declared: passing it to a function parameter that expects to be passed by reference, or assigning it by reference, results in an Error exception.

<?php

class Test {
    public readonly array $matches;

    public function __construct(string $subject) {
        // Illegal initialization by reference.
        preg_match('/\d+/', $subject, $this->matches);
        // Error: Cannot indirectly modify readonly property Test::$matches
    }
}

new Test('abc 42');
?>

      

[!NOTE] Specifying an explicit default value on readonly properties is not allowed, because a readonly property with a default value is essentially the same as a constant, and thus not particularly useful.

<?php

class Test {
    // Fatal error: Readonly property Test::$prop cannot have default value
    public readonly int $prop = 42;
}
?>

      

[!NOTE] Readonly properties cannot be unset once they are initialized. However, it is possible to unset a readonly property prior to initialization, from the scope where the property has been declared.

Modifications are not necessarily plain assignments, all of the following will also result in an Error exception:

<?php

class Test {
    public function __construct(
        public readonly int $i = 0,
        public readonly array $ary = [],
    ) {}
}

$test = new Test;
$test->i += 1;
$test->i++;
++$test->i;
$test->ary[] = 1;
$test->ary[0][] = 1;
unset($test->ary[0]);
$ref =& $test->i;
$test->i =& $ref;
byRef($test->i);
foreach ($test as &$prop);
?>

     

However, readonly properties do not preclude interior mutability. Objects (or resources) stored in readonly properties may still be modified internally:

<?php

class Test {
    public function __construct(public readonly object $obj) {}
}

$test = new Test(new stdClass);
// Legal interior mutation.
$test->obj->foo = 1;
// Illegal reassignment.
$test->obj = new stdClass;
?>

     

As of PHP 8.3.0, readonly properties can be reinitialized when cloning an object using the __clone() method.

Readonly properties and cloning

<?php
class Test1 {
    public readonly ?string $prop;

    public function __clone() {
        $this->prop = null;
    }

    public function setProp(string $prop): void {
        $this->prop = $prop;
    }
}

$test1 = new Test1;
$test1->setProp('foobar');

$test2 = clone $test1;
var_dump($test2->prop); // NULL
?>

     

[!NOTE] As of PHP 8.4.0, indirect modification of a readonly property within __clone(), such as acquiring a reference to it ($ref = ENTITY$this->prop), is no longer allowed. This was already forbidden during readonly initialization.

Dynamic properties

If trying to assign to a non-existent property on an ENTITY, PHP will automatically create a corresponding property. This dynamically created property will only be available on this class instance.

Dynamic properties are supported by stdClass and its subclasses. Other classes may enable similar behavior with AllowDynamicProperties or property overloading.

[!WARNING] Creating a dynamic property is deprecated as of PHP 8.2.0, unless the class is marked with the #[\AllowDynamicProperties] attribute. It is recommended to declare the property instead. To handle arbitrary property names, the class should implement the magic methods __get() and __set(). Marking the class with the attribute remains an option, but is generally considered a last resort.

Property Hooks

Property hooks, also known as "property accessors" in some other languages, are a way to intercept and override the read and write behavior of a property. This functionality serves two purposes:

  1. It allows for properties to be used directly, without get- and set- methods, while leaving the option open to add additional behavior in the future. That renders most boilerplate get/set methods unnecessary, even without using hooks.

  2. It allows for properties that describe an object without needing to store a value directly.

There are two hooks available on non-static properties: get and set. They allow overriding the read and write behavior of a property, respectively. Hooks are available for both typed and untyped properties.

A property may be "backed" or "virtual". A backed property is one that actually stores a value. Any property that has no hooks is backed. A virtual property is one that has hooks and those hooks do not interact with the property itself. In this case, the hooks are effectively the same as methods, and the object does not use any space to store a value for that property.

Property hooks are incompatible with readonly properties. If there is a need to restrict access to a get or set operation in addition to altering its behavior, use asymmetric property visibility.

[!NOTE] Property hooks were introduced in PHP 8.4.

Basic Hook Syntax

The general syntax for declaring a hook is as follows.

Property hooks (full version)

<?php
class Example
{
    private bool $modified = false;

    public string $foo = 'default value' {
        get {
            if ($this->modified) {
                return $this->foo . ' (modified)';
            }
            return $this->foo;
        }
        set(string $value) {
            $this->foo = strtolower($value);
            $this->modified = true;
        }
    }
}

$example = new Example();
$example->foo = 'changed';
print $example->foo;
?>

   

The $foo property ends in {}, rather than a semicolon. That indicates the presence of hooks. Both a get and set hook are defined, although it is allowed to define only one or the other. Both hooks have a body, denoted by {}, that may contain arbitrary code.

The set hook additionally allows specifying the type and name of an incoming value, using the same syntax as a method. The type must be either the same as the type of the property, or contravariant (wider) to it. For instance, a property of type string could have a set hook that accepts stringStringable, but not one that only accepts array.

At least one of the hooks references $this->foo, the property itself. That means the property will be "backed". When calling $example->foo = 'changed', the provided string will be first cast to lowercase, then saved to the backing value. When reading from the property, the previously saved value may conditionally be appended with additional text.

There are a number of shorthand syntax variants as well to handle common cases.

If the get hook is a single expression, then the {} may be omitted and replaced with an arrow expression.

Property get expression

This example is equivalent to the previous.

<?php
class Example
{
    private bool $modified = false;

    public string $foo = 'default value' {
        get => $this->foo . ($this->modified ? ' (modified)' : '');

        set(string $value) {
            $this->foo = strtolower($value);
            $this->modified = true;
        }
    }
}
?>

   

If the set hook's parameter type is the same as the property type (which is typical), it may be omitted. In that case, the value to set is automatically given the name $value.

Property set defaults

This example is equivalent to the previous.

<?php
class Example
{
    private bool $modified = false;

    public string $foo = 'default value' {
        get => $this->foo . ($this->modified ? ' (modified)' : '');

        set {
            $this->foo = strtolower($value);
            $this->modified = true;
        }
    }
}
?>

   

If the set hook is only setting a modified version of the passed in value, then it may also be simplified to an arrow expression. The value the expression evaluates to will be set on the backing value.

Property set expression

<?php
class Example
{
    private bool $modified = false;

    public string $foo = 'default value' {
        get => $this->foo . ($this->modified ? ' (modified)' : '');
        set => strtolower($value);
    }
}
?>

   

This example is not quite equivalent to the previous, as it does not also modify $this->modified. If multiple statements are needed in the set hook body, use the braces version.

A property may implement zero, one, or both hooks as the situation requires. All shorthand versions are mutually-independent. That is, using a short-get with a long-set, a short-set with an explicit type, and so on is all valid.

On a backed property, omitting a get or set hook means the default read or write behavior will be used.

[!NOTE] Hooks can be defined when using constructor property promotion. However, when doing so, values provided to the constructor must match the type associated with the property, regardless of what the set hook might allow.

Consider the following:

<?php
class Example
{
    public function __construct(
        public private(set) DateTimeInterface $created {
            set (string|DateTimeInterface $value) {
                if (is_string($value)) {
                    $value = new DateTimeImmutable($value);
                }
                $this->created = $value;
            }
        },
    ) {
    }
}

   

Internally, the engine decomposes this to the following:

<?php
class Example
{
    public private(set) DateTimeInterface $created {
        set (string|DateTimeInterface $value) {
            if (is_string($value)) {
                $value = new DateTimeImmutable($value);
            }
            $this->created = $value;
        }
    }

    public function __construct(
        DateTimeInterface $created,
    ) {
        $this->created = $created;
    }
}

   

Any attempts to set the property outside the constructor will allow either string or DateTimeInterface values, but the constructor will only allow DateTimeInterface. This is because the defined type for the property (DateTimeInterface) is used as the parameter type within the constructor signature, regardless of what the set hook allows.

If this kind of behavior is needed from the constructor, constructor property promotion cannot be used.

Virtual properties

Virtual properties are properties that have no backing value. A property is virtual if neither its get nor set hook references the property itself using exact syntax. That is, a property named $foo whose hook contains $this->foo will be backed. But the following is not a backed property, and will error:

Invalid virtual property

<?php
class Example
{
    public string $foo {
        get {
            $temp = __PROPERTY__;
            return $this->$temp; // Doesn't refer to $this->foo, so it doesn't count.
        }
    }
}
?>

   

For virtual properties, if a hook is omitted then that operation does not exist and trying to use it will produce an error. Virtual properties take up no memory space in an object. Virtual properties are suited for "derived" properties, such as those that are the combination of two other properties.

Virtual property

<?php
class Rectangle
{
    // A virtual property.
    public int $area {
        get => $this->h * $this->w;
    }

    public function __construct(public int $h, public int $w) {}
}

$s = new Rectangle(4, 5);
print $s->area; // prints 20
$s->area = 30; // Error, as there is no set operation defined.
?>

   

Defining both a get and set hook on a virtual property is also allowed.

Scoping

All hooks operate in the scope of the object being modified. That means they have access to all public, private, or protected methods of the object, as well as any public, private, or protected properties, including properties that may have their own property hooks. Accessing another property from within a hook does not bypass the hooks defined on that property.

The most notable implication of this is that non-trivial hooks may sub-call to an arbitrarily complex method if they wish.

Calling a method from a hook

<?php
class Person {
    public string $phone {
        set => $this->sanitizePhone($value);
    }

    private function sanitizePhone(string $value): string {
        $value = ltrim($value, '+');
        $value = ltrim($value, '1');

        if (!preg_match('/\d\d\d\-\d\d\d\-\d\d\d\d/', $value)) {
            throw new \InvalidArgumentException();
        }
        return $value;
    }
}
?>

   

References

Because the presence of hooks intercepts the read and write process for properties, they cause issues when acquiring a reference to a property or with indirect modification, such as $this->arrayProp['key'] = 'value';. That is because any attempted modification of the value by reference would bypass a set hook, if one is defined.

In the rare case that getting a reference to a property that has hooks defined is necessary, the get hook may be prefixed with ENTITY to cause it to return by reference. Defining both get and ENTITYget on the same property is a syntax error.

Defining both ENTITYget and set hooks on a backed property is not allowed. As noted above, writing to the value returned by reference would bypass the set hook. On virtual properties, there is no necessary common value shared between the two hooks, so defining both is allowed.

Writing to an index of an array property also involves an implicit reference. For that reason, writing to a backed array property with hooks defined is allowed if and only if it defines only a ENTITYget hook. On a virtual property, writing to the array returned from either get or ENTITYget is legal, but whether that has any impact on the object depends on the hook implementation.

Overwriting the entire array property is fine, and behaves the same as any other property. Only working with elements of the array requires special care.

Inheritance

Final hooks

Hooks may also be declared final, in which case they may not be overridden.

Final hooks

<?php
class User
{
    public string $username {
        final set => strtolower($value);
    }
}

class Manager extends User
{
    public string $username {
        // This is allowed
        get => strtoupper($this->username);

        // But this is NOT allowed, because set is final in the parent.
        set => strtoupper($value);
    }
}
?>

    

A property may also be declared final. A final property may not be redeclared by a child class in any way, which precludes altering hooks or widening its access.

Declaring hooks final on a property that is declared final is redundant, and will be silently ignored. This is the same behavior as final methods.

A child class may define or redefine individual hooks on a property by redefining the property and just the hooks it wishes to override. A child class may also add hooks to a property that had none. This is essentially the same as if the hooks were methods.

Hook inheritance

<?php
class Point
{
    public int $x;
    public int $y;
}

class PositivePoint extends Point
{
    public int $x {
        set {
            if ($value < 0) {
                throw new \InvalidArgumentException('Too small');
            }
            $this->x = $value;
        }
    }
}
?>

    

Each hook overrides parent implementations independently of each other. If a child class adds hooks, any default value set on the property is removed, and must be redeclared. That is consistent with how inheritance works on hook-less properties.

Accessing parent hooks

A hook in a child class may access the parent class's property using the parent::$prop keyword, followed by the desired hook. For example, parent::$propName::get(). It may be read as "access the prop defined on the parent class, and then run its get operation" (or set operation, as appropriate).

If not accessed this way, the parent class's hook is ignored. This behavior is consistent with how all methods work. This also offers a way to access the parent class's storage, if any. If there is no hook on the parent property, its default get/set behavior will be used. Hooks may not access any other hook except their own parent on their own property.

The example above could be rewritten as follows, which would allow for the Point class to add its own set hook in the future without issues (in the previous example, a hook added to the parent class would be ignored in the child).

Parent hook access (set)

<?php
class Point
{
    public int $x;
    public int $y;
}

class PositivePoint extends Point
{
    public int $x {
        set {
            if ($value < 0) {
                throw new \InvalidArgumentException('Too small');
            }
            parent::$x::set($value);
        }
    }
}
?>

    

An example of overriding only a get hook could be:

Parent hook access (get)

<?php
class Strings
{
    public string $val;
}

class CaseFoldingStrings extends Strings
{
    public bool $uppercase = true;

    public string $val {
        get => $this->uppercase
            ? strtoupper(parent::$val::get())
            : strtolower(parent::$val::get());
    }
}
?>

    

Serialization

PHP has a number of different ways in which an object may be serialized, either for public consumption or for debugging purposes. The behavior of hooks varies depending on the use case. In some cases, the raw backing value of a property will be used, bypassing any hooks. In others, the property will be read or written "through" the hook, just like any other normal read/write action.

var_dump

: Use raw value

serialize

: Use raw value

unserialize

: Use raw value

__serialize()

/

__unserialize()

: Custom logic, uses get/set hook

Array casting: Use raw value

var_export

: Use get hook

json_encode

: Use get hook

JsonSerializable

: Custom logic, uses get hook

get_object_vars

: Use get hook

get_mangled_object_vars

: Use raw value

Objects and references

One of the key-points of PHP OOP that is often mentioned is that "objects are passed by reference by default". This is not completely true. This section rectifies that general thought using some examples.

A PHP reference is an alias, which allows two different variables to write to the same value. In PHP, an object variable doesn't contain the object itself as value. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.

References and Objects

<?php
class A {
    public $foo = 1;
}  

$a = new A;
$b = $a;     // $a and $b are copies of the same identifier
             // ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."\n";


$c = new A;
$d = &$c;    // $c and $d are references
             // ($c,$d) = <id>

$d->foo = 2;
echo $c->foo."\n";


$e = new A;

function foo($obj) {
    // ($obj) = ($e) = <id>
    $obj->foo = 2;
}

foo($e);
echo $e->foo."\n";

?>  

   

ENTITY

2
2
2

Serializing objects - objects in sessions

serialize returns a string containing a byte-stream representation of any value that can be stored in PHP. unserialize can use this string to recreate the original variable values. Using serialize to save an object will save all variables in an object. The methods in an object will not be saved, only the name of the class.

In order to be able to unserialize an object, the class of that object needs to be defined. That is, if you have an object of class A and serialize this, you'll get a string that refers to class A and contains all values of variables contained in it. If you want to be able to unserialize an object of class A in another file, the definition of class A must be present in that file first. This can be done for example by storing the class definition of class A in an include file and including this file or making use of the spl_autoload_register function.

<?php
// A.php:
  
  class A {
      public $one = 1;
    
      public function show_one() {
          echo $this->one;
      }
  }
  
// page1.php:

  include "A.php";
  
  $a = new A;
  $s = serialize($a);
  // store $s somewhere where page2.php can find it.
  file_put_contents('store', $s);

// page2.php:
  
  // this is needed for the unserialize to work properly.
  include "A.php";

  $s = file_get_contents('store');
  $a = unserialize($s);

  // now use the function show_one() of the $a object.  
  $a->show_one();
?>

   

It is strongly recommended that if an application serializes objects, for use later in the application, the application includes the class definition for that object throughout the application. Not doing so might result in an object being unserialized without a class definition, which will result in PHP giving the object a class of __PHP_Incomplete_Class_Name, which has no methods and would render the object useless.

So if in the example above $a became part of a session by adding a new key to the $_SESSION superglobal array, you should include the file A.php on all of your pages, not only page1.php and page2.php.

Beyond the above advice, note that you can also hook into the serialization and unserialization events on an object using the __sleep() and __wakeup() methods. Using __sleep() also allows you to only serialize a subset of the object's properties.

Static Keyword

[!TIP] This page describes the use of the static keyword to define static methods and properties. static can also be used to define static variables, define static anonymous functions and for late static bindings. Please refer to those pages for information on those meanings of static.

Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. These can also be accessed statically within an instantiated class object.

Static methods

Because static methods are callable without an instance of the object created, the pseudo-variable $this is not available inside methods declared as static.

[!WARNING] Calling non-static methods statically throws an Error.

Prior to PHP 8.0.0, calling non-static methods statically was deprecated, and generated an E_DEPRECATED warning.

Static method example

<?php
class Foo {
    public static function aStaticMethod() {
        // ...
    }
}

Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod();
?> 

     

Static properties

Static properties are accessed using the Scope Resolution Operator (::) and cannot be accessed through the object operator (-ENTITY).

It's possible to reference the class using a variable. The variable's value cannot be a keyword (e.g. self, parent and static).

Static property example

<?php
class Foo
{
    public static $my_static = 'foo';

    public function staticValue() {
        return self::$my_static;
    }
}

class Bar extends Foo
{
    public function fooStatic() {
        return parent::$my_static;
    }
}


print Foo::$my_static . "\n";

$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n";      // Undefined "Property" my_static 

print $foo::$my_static . "\n";
$classname = 'Foo';
print $classname::$my_static . "\n";

print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>

    

ENTITY

foo
foo

Notice: Accessing static property Foo::$my_static as non static in /in/V0Rvv on line 23

Warning: Undefined property: Foo::$my_static in /in/V0Rvv on line 23

foo
foo
foo
foo

Traits

PHP implements a way to reuse code called Traits.

Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity, and avoids the typical problems associated with multiple inheritance and Mixins.

A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.

Trait example

<?php

trait TraitA {
    public function sayHello() {
        echo 'Hello';
    }
}

trait TraitB {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld
{
    use TraitA, TraitB; // A class can use multiple traits

    public function sayHelloWorld() {
        $this->sayHello();
        echo ' ';
        $this->sayWorld();
        echo "!\n";
    }
}

$myHelloWorld = new MyHelloWorld();
$myHelloWorld->sayHelloWorld();

?>

    

ENTITY

Hello World!

Precedence

An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.

[!NOTE] As of PHP 8.5.0, traits are bound to a class before its parent class; previously they were bound after. This more closely reflects the copy and paste semantics of traits. In particular, when a trait and the parent class both declare a property or constant of the same name, the trait's definition now takes precedence over the inherited one, whereas earlier versions raised a fatal error about an incompatible composition. Method resolution is unaffected. See the migration guide for details.

Precedence Order Example

An inherited method from a base class is overridden by the method inserted into MyHelloWorld from the SayWorld Trait. The behavior is the same for methods defined in the MyHelloWorld class. The precedence order is that methods from the current class override Trait methods, which in turn override methods from the base class.

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

    

ENTITY

Hello World!

Alternate Precedence Order Example

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();
?>

    

ENTITY

Hello Universe!

Multiple Traits

Multiple Traits can be inserted into a class by listing them in the use statement, separated by commas.

Multiple Traits Usage

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

    

ENTITY

Hello World!

Conflict Resolution

If two Traits insert a method with the same name, a fatal error is produced, if the conflict is not explicitly resolved.

To resolve naming conflicts between Traits used in the same class, the insteadof operator needs to be used to choose exactly one of the conflicting methods.

Since this only allows one to exclude methods, the as operator can be used to add an alias to one of the methods. Note the as operator does not rename the method and it does not affect any other method either.

Conflict Resolution

In this example, Talker uses the traits A and B. Since A and B have conflicting methods, it specifies that it uses the variant of smallTalk from trait B, and the variant of bigTalk from trait A.

The Aliased_Talker makes use of the as operator to be able to use B's bigTalk implementation under an additional alias talk.

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
?>

    

Changing Method Visibility

Using the as syntax, one can also adjust the visibility of the method in the exhibiting class.

Changing Method Visibility

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

// Change visibility of sayHello
class MyClass1 {
    use HelloWorld { sayHello as protected; }
}

// Alias method with changed visibility
// sayHello visibility not changed
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }
}
?>

    

Traits Composed from Traits

Just as classes can make use of traits, so can other traits. By using one or more traits in a trait definition, it can be composed partially or entirely of the members defined in those other traits.

Traits Composed from Traits

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

    

ENTITY

Hello World!

Abstract Trait Members

Traits support the use of abstract methods in order to impose requirements upon the exhibiting class. Public, protected, and private methods are supported. Prior to PHP 8.0.0, only public and protected abstract methods were supported.

[!CAUTION] As of PHP 8.0.0, the signature of a concrete method must follow the signature compatibility rules. Previously, its signature might be different.

Express Requirements by Abstract Methods

<?php
trait Hello {
    public function sayHelloWorld() {
        echo 'Hello'.$this->getWorld();
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}
?>

    

Static Trait Members

Traits can define static variables, static methods and static properties.

[!NOTE] As of PHP 8.1.0, calling a static method, or accessing a static property directly on a trait is deprecated. Static methods and properties should only be accessed on a class using the trait.

Static Variables

<?php

trait Counter
{
    public function inc()
    {
        static $c = 0;
        $c = $c + 1;
        echo "$c\n";
    }
}

class C1
{
    use Counter;
}

class C2
{
    use Counter;
}

$o = new C1();
$o->inc();
$p = new C2();
$p->inc();

?>

    

ENTITY

1
1

Static Methods

<?php

trait StaticExample
{
    public static function doSomething()
    {
        return 'Doing something';
    }
}

class Example
{
    use StaticExample;
}

echo Example::doSomething();

?>

    

ENTITY

Doing something

Static Properties

[!CAUTION] Prior to PHP 8.3.0, static properties defined in a trait were shared across all classes in the same inheritance hierarchy which used that trait. As of PHP 8.3.0, if a child class uses a trait with a static property, it will be considered distinct from the one defined in the parent class.

     
<?php

trait T
{
    public static $counter = 1;
}

class A
{
    use T;

    public static function incrementCounter()
    {
        static::$counter++;
    }
}

class B extends A
{
    use T;
}

A::incrementCounter();

echo A::$counter, "\n";
echo B::$counter, "\n";

?>

    

ENTITY

2
1

Properties

Traits can also define properties.

Defining Properties

<?php

trait PropertiesTrait
{
    public $x = 1;
}

class PropertiesExample
{
    use PropertiesTrait;
}

$example = new PropertiesExample();
$example->x;

?>

    

If a trait defines a property then a class can not define a property with the same name unless it is compatible (same visibility and type, readonly modifier, and initial value), otherwise a fatal error is issued.

Conflict Resolution

<?php
trait PropertiesTrait {
    public $same = true;
    public $different1 = false;
    public bool $different2;
    public bool $different3;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true;
    public $different1 = true; // Fatal error
    public string $different2; // Fatal error
    readonly protected bool $different3; // Fatal error
}
?>

    

ENTITY

Traits can, as of PHP 8.2.0, also define constants.

Defining Constants

<?php
trait ConstantsTrait {
    public const FLAG_MUTABLE = 1;
    final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
    use ConstantsTrait;
}

$example = new ConstantsExample;
echo $example::FLAG_MUTABLE;
?>

   

ENTITY

1

If a trait defines a constant then a class can not define a constant with the same name unless it is compatible (same visibility, initial value, and finality), otherwise a fatal error is issued.

Conflict Resolution

<?php
trait ConstantsTrait {
    public const FLAG_MUTABLE = 1;
    final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
    use ConstantsTrait;
    public const FLAG_IMMUTABLE = 5; // Fatal error
}
?>

   

Final methods

As of PHP 8.3.0, the final modifier can be applied using the as operator to methods imported from traits. This can be used to prevent child classes from overriding the method. However, the class that uses the trait can still override the method.

Defining a method coming from a trait as final

    
<?php

trait CommonTrait
{
    public function method()
    {
        echo 'Hello';
    }
}

class FinalExampleA
{
    use CommonTrait {
        CommonTrait::method as final; // The 'final' prevents child classes from overriding the method
    }
}

class FinalExampleB extends FinalExampleA
{
    public function method() {}
}

?>

   

ENTITY

Fatal error: Cannot override final method FinalExampleA::method() in ...

Covariance and Contravariance

In PHP 7.2.0, partial contravariance was introduced by removing type restrictions on parameters in a child method. As of PHP 7.4.0, full covariance and contravariance support was added.

Covariance allows a child's method to return a more specific type than the return type of its parent's method. Contravariance allows a parameter type to be less specific in a child method, than that of its parent.

A type declaration is considered more specific in the following case:

A type declaration is considered less specific if the opposite is true.

Covariance

To illustrate how covariance works, a simple abstract parent class, Animal is created. Animal will be extended by child classes, Cat, and Dog.

<?php

abstract class Animal
{
    protected string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    abstract public function speak();
}

class Dog extends Animal
{
    public function speak()
    {
        echo $this->name . " barks";
    }
}

class Cat extends Animal 
{
    public function speak()
    {
        echo $this->name . " meows";
    }
}

   

Note that there aren't any methods which return values in this example. A few factories will be added which return a new object of class type Animal, Cat, or Dog.

<?php

interface AnimalShelter
{
    public function adopt(string $name): Animal;
}

class CatShelter implements AnimalShelter
{
    public function adopt(string $name): Cat // instead of returning class type Animal, it can return class type Cat
    {
        return new Cat($name);
    }
}

class DogShelter implements AnimalShelter
{
    public function adopt(string $name): Dog // instead of returning class type Animal, it can return class type Dog
    {
        return new Dog($name);
    }
}

$kitty = (new CatShelter)->adopt("Ricky");
$kitty->speak();
echo "\n";

$doggy = (new DogShelter)->adopt("Mavrick");
$doggy->speak();

   

ENTITY

Ricky meows
Mavrick barks

[!NOTE] As of PHP 8.5.0, when a parent method declares static as its return type, an overriding method in a final class may declare self or the class's own type as its return type instead, since these are equivalent to static in a class that cannot be extended further. See the migration guide for details.

Contravariance

Continuing with the previous example with the classes Animal, Cat, and Dog, a class called Food and AnimalFood will be included, and a method eat(AnimalFood $food) is added to the Animal abstract class.

<?php

class Food {}

class AnimalFood extends Food {}

abstract class Animal
{
    protected string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function eat(AnimalFood $food)
    {
        echo $this->name . " eats " . get_class($food);
    }
}

   

In order to see the behavior of contravariance, the eat method is overridden in the Dog class to allow any Food type object. The Cat class remains unchanged.

<?php

class Dog extends Animal
{
    public function eat(Food $food) {
        echo $this->name . " eats " . get_class($food);
    }
}

   

The next example will show the behavior of contravariance.

<?php

$kitty = (new CatShelter)->adopt("Ricky");
$catFood = new AnimalFood();
$kitty->eat($catFood);
echo "\n";

$doggy = (new DogShelter)->adopt("Mavrick");
$banana = new Food();
$doggy->eat($banana);

   

ENTITY

Ricky eats AnimalFood
Mavrick eats Food

But what happens if $kitty tries to eat the $banana?

$kitty->eat($banana);

   

ENTITY

Fatal error: Uncaught TypeError: Argument 1 passed to Animal::eat() must be an instance of AnimalFood, instance of Food given

Property variance

By default, properties are neither covariant nor contravariant, hence invariant. That is, their type may not change in a child class at all. The reason for that is "get" operations must be covariant, and "set" operations must be contravariant. The only way for a property to satisfy both requirements is to be invariant.

As of PHP 8.4.0, with the addition of abstract properties (on an interface or abstract class) and virtual properties, it is possible to declare a property that has only a get or set operation. As a result, abstract properties or virtual properties that have only a "get" operation required may be covariant. Similarly, an abstract property or virtual property that has only a "set" operation required may be contravariant.

Once a property has both a get and set operation, however, it is no longer covariant or contravariant for further extension. That is, it is now invariant.

Property type variance

<?php
class Animal {}
class Dog extends Animal {}
class Poodle extends Dog {}

interface PetOwner
{
    // Only a get operation is required, so this may be covariant.
    public Animal $pet { get; }
}

class DogOwner implements PetOwner
{
    // This may be a more restrictive type since the "get" side
    // still returns an Animal.  However, as a native property
    // children of this class may not change the type anymore.
    public Dog $pet;
}

class PoodleOwner extends DogOwner
{
    // This is NOT ALLOWED, because DogOwner::$pet has both
    // get and set operations defined and required.
    public Poodle $pet;
}
?>

   

Visibility

The visibility of a property, a method or (as of PHP 7.1.0) a constant can be defined by prefixing the declaration with the keywords public, protected or private. Class members declared public can be accessed everywhere. Members declared protected can be accessed only within the class itself and by inheriting and parent classes. Members declared as private may only be accessed by the class that defines the member.

Property Visibility

Class properties may be defined as public, private, or protected. Properties declared without any explicit visibility keyword are defined as public.

Property declaration

<?php
/**
 * Define MyClass
 */
class MyClass
{
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // We can redeclare the public and protected properties, but not private
    public $public = 'Public2';
    protected $protected = 'Protected2';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj2 = new MyClass2();
echo $obj2->public; // Works
echo $obj2->protected; // Fatal Error
echo $obj2->private; // Undefined
$obj2->printHello(); // Shows Public2, Protected2, Undefined

?> 

    

Asymmetric Property Visibility

As of PHP 8.4, object properties may also have their visibility set asymmetrically, with a different scope for reading (get) and writing (set). Specifically, the set visibility may be specified separately, provided it is not more permissive than the default visibility.

Asymmetric Property visibility

<?php
class Book
{
    public function __construct(
        public private(set) string $title,
        public protected(set) string $author,
        protected private(set) int $pubYear,
    ) {}
}

class SpecialBook extends Book
{
    public function update(string $author, int $year): void
    {
        $this->author = $author; // OK
        $this->pubYear = $year; // Fatal Error
    }
}

$b = new Book('How to PHP', 'Peter H. Peterson', 2024);

echo $b->title; // Works
echo $b->author; // Works
echo $b->pubYear; // Fatal Error

$b->title = 'How not to PHP'; // Fatal Error
$b->author = 'Pedro H. Peterson'; // Fatal Error
$b->pubYear = 2023; // Fatal Error
?>

     

As of PHP 8.5, set visibility may also be applied to static properties of classes.

Asymmetric Static Property Visibility

<?php
class Manager
{
    public private(set) static int $calls = 0;

    public function doAThing(): string
    {
        self::$calls++;
        // Do other stuff.
        return "some string";
    }
}

$m = new Manager();

$m->doAThing(); // Works
echo Manager::$calls; // Works
Manager::$calls = 5; // Fatal error
?>

     

ENTITY

1
Fatal error: Uncaught Error: Cannot modify private(set) property Manager::$calls from global scope in /some/file.php

There are a few caveats regarding asymmetric visibility:

[!NOTE] Spaces are not allowed in the set-visibility declaration. private(set) is correct. private( set ) is not correct and will result in a parse error.

When a class extends another, the child class may redefine any property that is not final. When doing so, it may widen either the main visibility or the set visibility, provided that the new visibility is the same or wider than the parent class. However, be aware that if a private property is overridden, it does not actually change the parent's property but creates a new property with a different internal name.

Asymmetric Property inheritance

<?php
class Book
{
    protected string $title;
    public protected(set) string $author;
    protected private(set) int $pubYear;
}

class SpecialBook extends Book
{
    public protected(set) string $title; // OK, as reading is wider and writing the same.
    public string $author; // OK, as reading is the same and writing is wider.
    public protected(set) int $pubYear; // Fatal Error. private(set) properties are final.
}
?>

     

Method Visibility

Class methods may be defined as public, private, or protected. Methods declared without any explicit visibility keyword are defined as public.

Method Declaration

<?php
/**
 * Define MyClass
 */
class MyClass
{
    // Declare a public constructor
    public function __construct() { }

    // Declare a public method
    public function MyPublic() { }

    // Declare a protected method
    protected function MyProtected() { }

    // Declare a private method
    private function MyPrivate() { }

    // This is public
    function Foo()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}

$myclass = new MyClass;
$myclass->MyPublic(); // Works
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate(); // Fatal Error
$myclass->Foo(); // Public, Protected and Private work


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // This is public
    function Foo2()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate(); // Fatal Error
    }
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Works
$myclass2->Foo2(); // Public and Protected work, not Private

class Bar 
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublic\n";
    }
    
    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}

class Foo extends Bar 
{
    public function testPublic() {
        echo "Foo::testPublic\n";
    }
    
    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}

$myFoo = new Foo();
$myFoo->test(); // Bar::testPrivate 
                // Foo::testPublic
?>

    

Constant Visibility

As of PHP 7.1.0, class constants may be defined as public, private, or protected. Constants declared without any explicit visibility keyword are defined as public.

Constant Declaration as of PHP 7.1.0

<?php
/**
 * Define MyClass
 */
class MyClass
{
    // Declare a public constant
    public const MY_PUBLIC = 'public';

    // Declare a protected constant
    protected const MY_PROTECTED = 'protected';

    // Declare a private constant
    private const MY_PRIVATE = 'private';

    public function foo()
    {
        echo self::MY_PUBLIC;
        echo self::MY_PROTECTED;
        echo self::MY_PRIVATE;
    }
}

$myclass = new MyClass();
MyClass::MY_PUBLIC; // Works
MyClass::MY_PROTECTED; // Fatal Error
MyClass::MY_PRIVATE; // Fatal Error
$myclass->foo(); // Public, Protected and Private work


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // This is public
    function foo2()
    {
        echo self::MY_PUBLIC;
        echo self::MY_PROTECTED;
        echo self::MY_PRIVATE; // Fatal Error
    }
}

$myclass2 = new MyClass2;
echo MyClass2::MY_PUBLIC; // Works
$myclass2->foo2(); // Public and Protected work, not Private
?>

    

Visibility from other objects

Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.

Accessing private members of the same object type

<?php
class Test
{
    private $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    private function bar()
    {
        echo 'Accessed the private method.';
    }

    public function baz(Test $other)
    {
        // We can change the private property:
        $other->foo = 'hello';
        var_dump($other->foo);

        // We can also call the private method:
        $other->bar();
    }
}

$test = new Test('test');

$test->baz(new Test('other'));
?>

    

ENTITY

string(5) "hello"
Accessed the private method.

Operators

An operator is something that takes one or more values (or expressions, in programming jargon) and yields another value (so that the construction itself becomes an expression).

Operators can be grouped according to the number of values they take. Unary operators take only one value, for example ! (the logical not operator) or ++ (the increment operator). Binary operators take two values, such as the familiar arithmetical operators + (plus) and - (minus), and the majority of PHP operators fall into this category. Finally, there is a single ternary operator, ? :, which takes three values; this is usually referred to simply as "the ternary operator" (although it could perhaps more properly be called the conditional operator).

A full list of PHP operators follows in the section Operator Precedence. The section also explains operator precedence and associativity, which govern exactly how expressions containing several different operators are evaluated.

There is a PECL extension that allows for overloading of some operators for objects. For more information, see the Operator Overloading for Objects section.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

Arithmetic Operators

Remember basic arithmetic from school? These work just like those.

Example Name Result
+$a Identity Conversion of $a to int or float as appropriate.
-$a Negation Opposite of $a.
$a + $b Addition Sum of $a and $b.
$a - $b Subtraction Difference of $a and $b.
$a * $b Multiplication Product of $a and $b.
$a / $b Division Quotient of $a and $b.
$a % $b Modulo Remainder of $a divided by $b.
$a ** $b Exponentiation Result of raising $a to the $b'th power.

Arithmetic Operators

The division operator / returns a float value unless the two operands are int (or numeric strings which are type juggled to int) and the numerator is a multiple of the divisor, in which case an integer value will be returned. For integer division, see intdiv.

Operands of modulo are converted to int before processing. For floating-point modulo, see fmod.

The result of the modulo operator % has the same sign as the dividend — that is, the result of $a % $b will have the same sign as $a. For example:

The Modulo Operator

<?php
var_dump(5 % 3);
var_dump(5 % -3);
var_dump(-5 % 3);
var_dump(-5 % -3);
?>

   

ENTITY

int(2)
int(2)
int(-2)
int(-2)

ENTITY

Math functions

Array Operators

Example Name Result
$a + $b Union Union of $a and $b.
$a == $b Equality ENTITY if $a and $b have the same key/value pairs.
$a === $b Identity ENTITY if $a and $b have the same key/value pairs in the same order and of the same types.
$a != $b Inequality ENTITY if $a is not equal to $b.
$a ENTITYENTITY $b Inequality ENTITY if $a is not equal to $b.
$a !== $b Non-identity ENTITY if $a is not identical to $b.

Array Operators

The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.

Array Append Operator

<?php
$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");

$c = $a + $b; // Union of $a and $b
echo "Union of \$a and \$b: \n";
var_dump($c);

$c = $b + $a; // Union of $b and $a
echo "Union of \$b and \$a: \n";
var_dump($c);

$a += $b; // Union of $a += $b is $a and $b
echo "Union of \$a += \$b: \n";
var_dump($a);
?>

   

ENTITY

Union of $a and $b:
array(3) {
  ["a"]=>
  string(5) "apple"
  ["b"]=>
  string(6) "banana"
  ["c"]=>
  string(6) "cherry"
}
Union of $b and $a:
array(3) {
  ["a"]=>
  string(4) "pear"
  ["b"]=>
  string(10) "strawberry"
  ["c"]=>
  string(6) "cherry"
}
Union of $a += $b:
array(3) {
  ["a"]=>
  string(5) "apple"
  ["b"]=>
  string(6) "banana"
  ["c"]=>
  string(6) "cherry"
}

   

Elements of arrays are equal for the comparison if they have the same key and value.

Comparing arrays

<?php
$a = array("apple", "banana");
$b = array(1 => "banana", "0" => "apple");

var_dump($a == $b); // bool(true)
var_dump($a === $b); // bool(false)
?>

   

ENTITY

Array type, Array functions

Assignment Operators

The basic assignment operator is "=". Your first inclination might be to think of this as "equal to". Don't. It really means that the left operand gets set to the value of the expression on the right (that is, "gets set to").

The value of an assignment expression is the value assigned. That is, the value of "$a = 3" is 3. This allows you to do some tricky things:

Nested Assignments

<?php
$a = ($b = 4) + 5; // $a is equal to 9 now, and $b has been set to 4.
var_dump($a);
?>

   

In addition to the basic assignment operator, there are "combined operators" for all of the binary arithmetic, array union and string operators that allow you to use a value in an expression and then set its value to the result of that expression. For example:

Combined Assignments

<?php
$a = 3;
$a += 5; // sets $a to 8, as if we had said: $a = $a + 5;
$b = "Hello ";
$b .= "There!"; // sets $b to "Hello There!", just like $b = $b . "There!";

var_dump($a, $b);
?>

   

Note that the assignment copies the original variable to the new one (assignment by value), so changes to one will not affect the other. This may also have relevance if you need to copy something like a large array inside a tight loop.

An exception to the usual assignment by value behaviour within PHP occurs with objects, which are assigned by reference. Objects may be explicitly copied via the clone keyword.

Assignment by Reference

Assignment by reference is also supported, using the "$var = ENTITY$othervar;" syntax. Assignment by reference means that both variables end up pointing at the same data, and nothing is copied anywhere.

Assigning by reference

<?php
$a = 3;
$b = &$a; // $b is a reference to $a

print "$a\n"; // prints 3
print "$b\n"; // prints 3

$a = 4; // change $a

print "$a\n"; // prints 4
print "$b\n"; // prints 4 as well, since $b is a reference to $a, which has
              // been changed
?>

    

The new operator returns a reference automatically, as such assigning the result of new by reference is an error.

new Operator By-Reference

<?php
class C {}

$o = &new C;
?>

    

ENTITY

Parse error: syntax error, unexpected token ";", expecting "("

More information on references and their potential uses can be found in the References Explained section of the manual.

Arithmetic Assignment Operators

Example Equivalent Operation
$a += $b $a = $a + $b Addition
$a -= $b $a = $a - $b Subtraction
$a *= $b $a = $a * $b Multiplication
$a /= $b $a = $a / $b Division
$a %= $b $a = $a % $b Modulus
$a **= $b $a = $a ** $b Exponentiation

Bitwise Assignment Operators

Example Equivalent Operation
$a ENTITY= $b $a = $a ENTITY $b Bitwise And
$a |= $b $a = $a | $b Bitwise Or
$a ^= $b $a = $a ^ $b Bitwise Xor
$a ENTITYENTITY= $b $a = $a ENTITYENTITY $b Left Shift
$a ENTITYENTITY= $b $a = $a ENTITYENTITY $b Right Shift

Other Assignment Operators

Example Equivalent Operation
$a .= $b $a = $a . $b String Concatenation
$a ??= $b $a = $a ?? $b Null Coalesce

ENTITY

arithmetic operators, bitwise operators, null coalescing operator

Bitwise Operators

Bitwise operators allow evaluation and manipulation of specific bits within an integer.

Example Name Result
$a ENTITY $b And Bits that are set in both $a and $b are set.
`$a $b` Or (inclusive or)
$a ^ $b Xor (exclusive or) Bits that are set in $a or $b but not both are set.
~ $a Not Bits that are set in $a are not set, and vice versa.
$a ENTITYENTITY $b Shift left Shift the bits of $a $b steps to the left (each step means "multiply by two")
$a ENTITYENTITY $b Shift right Shift the bits of $a $b steps to the right (each step means "divide by two")

Bitwise Operators

Bit shifting in PHP is arithmetic. Bits shifted off either end are discarded. Left shifts have zeros shifted in on the right while the sign bit is shifted out on the left, meaning the sign of an operand is not preserved. Right shifts have copies of the sign bit shifted in on the left, meaning the sign of an operand is preserved.

Use parentheses to ensure the desired precedence. For example, $a ENTITY $b == true evaluates the equivalency then the bitwise and; while ($a ENTITY $b) == true evaluates the bitwise and then the equivalency.

If both operands for the ENTITY, | and ^ operators are strings, then the operation will be performed on the ASCII values of the characters that make up the strings and the result will be a string. In all other cases, both operands will be converted to integers and the result will be an integer.

If the operand for the ~ operator is a string, the operation will be performed on the ASCII values of the characters that make up the string and the result will be a string, otherwise the operand and the result will be treated as integers.

Both operands and the result for the ENTITYENTITY and ENTITYENTITY operators are always treated as integers.

PHP's error_reporting ini setting uses bitwise values, providing a real-world demonstration of turning bits off. To show all errors, except for notices, the php.ini file instructions say to use: E_ALL ENTITY ~E_NOTICE


     This works by starting with E_ALL:
     00000000000000000111011111111111
     Then taking the value of E_NOTICE...
     00000000000000000000000000001000
     ... and inverting it via ~:
     11111111111111111111111111110111
     Finally, it uses AND (ENTITY) to find the bits turned
     on in both values:
     00000000000000000111011111110111
    

Another way to accomplish that is using XOR (^) to find bits that are on in only one value or the other: E_ALL ^ E_NOTICE

error_reporting can also be used to demonstrate turning bits on. The way to show just errors and recoverable errors is: E_ERROR | E_RECOVERABLE_ERROR


     This process combines E_ERROR
     00000000000000000000000000000001
     and
     00000000000000000001000000000000
     using the OR (|) operator
     to get the bits turned on in either value:
     00000000000000000001000000000001
    

Bitwise AND, OR and XOR operations on integers

<?php
/*
 * Ignore the top section,
 * it is just formatting to make output clearer.
 */

$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
        . ' %3$s (%4$2d = %4$04b)' . "\n";

echo <<<EOH
 ---------     ---------  -- ---------
 result        value      op test
 ---------     ---------  -- ---------
EOH;


/*
 * Here are the examples.
 */

$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;

echo "\n Bitwise AND \n";
foreach ($values as $value) {
    $result = $value & $test;
    printf($format, $result, $value, '&', $test);
}

echo "\n Bitwise Inclusive OR \n";
foreach ($values as $value) {
    $result = $value | $test;
    printf($format, $result, $value, '|', $test);
}

echo "\n Bitwise Exclusive OR (XOR) \n";
foreach ($values as $value) {
    $result = $value ^ $test;
    printf($format, $result, $value, '^', $test);
}
?>

   

ENTITY

 ---------     ---------  -- ---------
 result        value      op test
 ---------     ---------  -- ---------
 Bitwise AND
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)

 Bitwise Inclusive OR
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101)

 Bitwise Exclusive OR (XOR)
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)

Bitwise XOR operations on strings

<?php
echo 12 ^ 9, PHP_EOL; // Outputs '5'

echo "12" ^ "9", PHP_EOL; // Outputs the Backspace character (ascii 8)
                          // ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8

echo "hallo" ^ "hello", PHP_EOL; // Outputs the ascii values #0 #4 #0 #0 #0
                                 // 'a' ^ 'e' = #4

echo 2 ^ "3", PHP_EOL; // Outputs 1
                       // 2 ^ ((int) "3") == 1

echo "2" ^ 3, PHP_EOL; // Outputs 1
                       // ((int) "2") ^ 3 == 1
?>

   

Bit shifting on integers

<?php
/*
 * Here are the examples.
 */

echo "\n--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---\n";

$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copy of sign bit shifted into left side');

$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);

$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits shift out right side');

$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'same result as above; can not shift beyond 0');


echo "\n--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---\n";

$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copy of sign bit shifted into left side');

$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits shift out right side');

$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'same result as above; can not shift beyond -1');


echo "\n--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---\n";

$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'zeros fill in right side');

$val = 4;
$places = (PHP_INT_SIZE * 8) - 4;
$res = $val << $places;
p($res, $val, '<<', $places);

$val = 4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places, 'sign bits get shifted out');

$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bits shift out left side');


echo "\n--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---\n";

$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'zeros fill in right side');

$val = -4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places);

$val = -4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bits shift out left side, including sign bit');


/*
 * Ignore this bottom section,
 * it is just formatting to make output clearer.
 */

function p($res, $val, $op, $places, $note = '') {
    $format = '%0' . (PHP_INT_SIZE * 8) . "b\n";

    printf("Expression: %d = %d %s %d\n", $res, $val, $op, $places);

    echo " Decimal:\n";
    printf("  val=%d\n", $val);
    printf("  res=%d\n", $res);

    echo " Binary:\n";
    printf('  val=' . $format, $val);
    printf('  res=' . $format, $res);

    if ($note) {
        echo " NOTE: $note\n";
    }

    echo "\n\n";
}
?>

   

ENTITY

--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
 Decimal:
  val=4
  res=2
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000010
 NOTE: copy of sign bit shifted into left side

Expression: 1 = 4 >> 2
 Decimal:
  val=4
  res=1
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000001

Expression: 0 = 4 >> 3
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: bits shift out right side

Expression: 0 = 4 >> 4
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: same result as above; can not shift beyond 0


--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
 Decimal:
  val=-4
  res=-2
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111110
 NOTE: copy of sign bit shifted into left side

Expression: -1 = -4 >> 2
 Decimal:
  val=-4
  res=-1
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 NOTE: bits shift out right side

Expression: -1 = -4 >> 3
 Decimal:
  val=-4
  res=-1
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111111
 NOTE: same result as above; can not shift beyond -1


--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
 Decimal:
  val=4
  res=8
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000001000
 NOTE: zeros fill in right side

Expression: 1073741824 = 4 << 28
 Decimal:
  val=4
  res=1073741824
 Binary:
  val=00000000000000000000000000000100
  res=01000000000000000000000000000000

Expression: -2147483648 = 4 << 29
 Decimal:
  val=4
  res=-2147483648
 Binary:
  val=00000000000000000000000000000100
  res=10000000000000000000000000000000
 NOTE: sign bits get shifted out

Expression: 0 = 4 << 30
 Decimal:
  val=4
  res=0
 Binary:
  val=00000000000000000000000000000100
  res=00000000000000000000000000000000
 NOTE: bits shift out left side


--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
 Decimal:
  val=-4
  res=-8
 Binary:
  val=11111111111111111111111111111100
  res=11111111111111111111111111111000
 NOTE: zeros fill in right side

Expression: -2147483648 = -4 << 29
 Decimal:
  val=-4
  res=-2147483648
 Binary:
  val=11111111111111111111111111111100
  res=10000000000000000000000000000000

Expression: 0 = -4 << 30
 Decimal:
  val=-4
  res=0
 Binary:
  val=11111111111111111111111111111100
  res=00000000000000000000000000000000
 NOTE: bits shift out left side, including sign bit

ENTITY

--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
 Decimal:
  val=4
  res=2
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000010
 NOTE: copy of sign bit shifted into left side

Expression: 1 = 4 >> 2
 Decimal:
  val=4
  res=1
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000001

Expression: 0 = 4 >> 3
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits shift out right side

Expression: 0 = 4 >> 4
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: same result as above; can not shift beyond 0


--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
 Decimal:
  val=-4
  res=-2
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111110
 NOTE: copy of sign bit shifted into left side

Expression: -1 = -4 >> 2
 Decimal:
  val=-4
  res=-1
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 NOTE: bits shift out right side

Expression: -1 = -4 >> 3
 Decimal:
  val=-4
  res=-1
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111111
 NOTE: same result as above; can not shift beyond -1


--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
 Decimal:
  val=4
  res=8
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000001000
 NOTE: zeros fill in right side

Expression: 4611686018427387904 = 4 << 60
 Decimal:
  val=4
  res=4611686018427387904
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0100000000000000000000000000000000000000000000000000000000000000

Expression: -9223372036854775808 = 4 << 61
 Decimal:
  val=4
  res=-9223372036854775808
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=1000000000000000000000000000000000000000000000000000000000000000
 NOTE: sign bits get shifted out

Expression: 0 = 4 << 62
 Decimal:
  val=4
  res=0
 Binary:
  val=0000000000000000000000000000000000000000000000000000000000000100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits shift out left side


--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
 Decimal:
  val=-4
  res=-8
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1111111111111111111111111111111111111111111111111111111111111000
 NOTE: zeros fill in right side

Expression: -9223372036854775808 = -4 << 61
 Decimal:
  val=-4
  res=-9223372036854775808
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=1000000000000000000000000000000000000000000000000000000000000000

Expression: 0 = -4 << 62
 Decimal:
  val=-4
  res=0
 Binary:
  val=1111111111111111111111111111111111111111111111111111111111111100
  res=0000000000000000000000000000000000000000000000000000000000000000
 NOTE: bits shift out left side, including sign bit

[!WARNING] Use functions from the gmp extension for bitwise manipulation on numbers beyond PHP_INT_MAX.

ENTITY

pack, unpack, gmp_and, gmp_or, gmp_xor, gmp_testbit, gmp_clrbit

Comparison Operators

Comparison operators, as their name implies, allow you to compare two values. You may also be interested in viewing the type comparison tables, as they show examples of various type related comparisons.

Example Name Result
$a == $b Equal ENTITY if $a is equal to $b after type juggling.
$a === $b Identical ENTITY if $a is equal to $b, and they are of the same type.
$a != $b Not equal ENTITY if $a is not equal to $b after type juggling.
$a ENTITYENTITY $b Not equal ENTITY if $a is not equal to $b after type juggling.
$a !== $b Not identical ENTITY if $a is not equal to $b, or they are not of the same type.
$a ENTITY $b Less than ENTITY if $a is strictly less than $b.
$a ENTITY $b Greater than ENTITY if $a is strictly greater than $b.
$a ENTITY= $b Less than or equal to ENTITY if $a is less than or equal to $b.
$a ENTITY= $b Greater than or equal to ENTITY if $a is greater than or equal to $b.
$a ENTITY=ENTITY $b Spaceship An int less than, equal to, or greater than zero when $a is less than, equal to, or greater than $b, respectively.

Comparison Operators

If both operands are numeric strings, or one operand is a number and the other one is a numeric string, then the comparison is done numerically. These rules also apply to the switch statement. The type conversion does not take place when the comparison is === or !== as this involves comparing the type as well as the value.

[!WARNING] Prior to PHP 8.0.0, if a string is compared to a number or a numeric string then the string was converted to a number before performing the comparison. This can lead to surprising results as can be seen with the following example:

<?php
var_dump(0 == "a");
var_dump("1" == "01");
var_dump("10" == "1e1");
var_dump(100 == "1e2");

switch ("a") {
case 0:
    echo "0";
    break;
case "a":
    echo "a";
    break;
}
?>

    

ENTITY

bool(true)
bool(true)
bool(true)
bool(true)
0

ENTITY

bool(false)
bool(true)
bool(true)
bool(true)
a

Comparison Operators

<?php
// Integers
echo 1 <=> 1, ' '; // 0
echo 1 <=> 2, ' '; // -1
echo 2 <=> 1, ' '; // 1

// Floats
echo 1.5 <=> 1.5, ' '; // 0
echo 1.5 <=> 2.5, ' '; // -1
echo 2.5 <=> 1.5, ' '; // 1

// Strings
echo "a" <=> "a", ' '; // 0
echo "a" <=> "b", ' '; // -1
echo "b" <=> "a", ' '; // 1

echo "a" <=> "aa", ' ';  // -1
echo "zz" <=> "aa", ' '; // 1

// Arrays
echo [] <=> [], ' ';               // 0
echo [1, 2, 3] <=> [1, 2, 3], ' '; // 0
echo [1, 2, 3] <=> [], ' ';        // 1
echo [1, 2, 3] <=> [1, 2, 1], ' '; // 1
echo [1, 2, 3] <=> [1, 2, 4], ' '; // -1

// Objects
$a = (object) ["a" => "b"];
$b = (object) ["a" => "b"];
echo $a <=> $b, ' '; // 0

$a = (object) ["a" => "b"];
$b = (object) ["a" => "c"];
echo $a <=> $b, ' '; // -1

$a = (object) ["a" => "c"];
$b = (object) ["a" => "b"];
echo $a <=> $b, ' '; // 1

// not only values are compared; keys must match
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo $a <=> $b, ' '; // 1

?>

   

For various types, comparison is done according to the following table (in order).

Type of Operand 1 Type of Operand 2 Result
null or string string Convert ENTITY to "", numerical or lexical comparison
bool or null anything Convert both sides to bool, ENTITY ENTITY ENTITY
object object Built-in classes can define its own comparison, different classes are incomparable, same class see Object Comparison
string, resource, int or float string, resource, int or float Translate strings and resources to numbers, usual math
array array Array with fewer members is smaller, if key from operand 1 is not found in operand 2 then arrays are incomparable, otherwise - compare value by value (see following example)
object anything object is always greater
array anything array is always greater

Comparison with Various Types {#language.operators.comparison.types}

Boolean/null comparison

<?php
// Bool and null are compared as bool always
var_dump(1 == TRUE);  // TRUE - same as (bool) 1 == TRUE
var_dump(0 == FALSE); // TRUE - same as (bool) 0 == FALSE
var_dump(100 < TRUE); // FALSE - same as (bool) 100 < TRUE
var_dump(-10 < FALSE);// FALSE - same as (bool) -10 < FALSE
var_dump(min(-100, -10, NULL, 10, 100)); // NULL - (bool) NULL < (bool) -100 is FALSE < TRUE
?>

   

Transcription of standard array comparison

<?php
// Arrays are compared like this with standard comparison operators as well as the spaceship operator.
function standard_array_compare($op1, $op2)
{
    if (count($op1) < count($op2)) {
        return -1; // $op1 < $op2
    } elseif (count($op1) > count($op2)) {
        return 1; // $op1 > $op2
    }
    foreach ($op1 as $key => $val) {
        if (!array_key_exists($key, $op2)) {
            return 1;
        } elseif ($val < $op2[$key]) {
            return -1;
        } elseif ($val > $op2[$key]) {
            return 1;
        }
    }
    return 0; // $op1 == $op2
}
?>

   

[!WARNING] Because of the way floats are represented internally, you should not test two floats for equality.

See the documentation for float for more information.

[!NOTE] Be aware that PHP's type juggling is not always obvious when comparing values of different types, particularly comparing ENTITYs to ENTITYs or ENTITYs to ENTITYs. It is therefore generally advisable to use === and !== comparisons rather than == and != in most cases.

[!NOTE] Encountering recursion during comparison, for example when comparing an array or object that contains a reference to itself, throws an Error as of PHP 8.4.0; previously, it resulted in a fatal error.

Incomparable Values

While identity comparison (=== and !==) can be applied to arbitrary values, the other comparison operators should only be applied to comparable values. The result of comparing incomparable values is undefined, and should not be relied upon.

[!NOTE] As of PHP 8.5.0, loosely comparing an object that is not comparable (such as an enum, CurlHandle, or another internal class) against a bool using == or != consistently evaluates as if the object were cast to bool, that is (bool) $object. Because such an object always casts to ENTITY, it is equal to ENTITY and not equal to ENTITY. Prior to PHP 8.5.0, this only applied when comparing against a boolean literal ($object == true); comparing against a boolean value held in a variable always returned ENTITY. See the migration guide for details.

ENTITY

strcasecmp, strcmp, Array operators, Types

Ternary Operator

Another conditional operator is the "?:" (or ternary) operator.

Assigning a default value

<?php
// Example usage for: Ternary Operator
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

// The above is identical to this if/else statement
if (empty($_POST['action'])) {
    $action = 'default';
} else {
    $action = $_POST['action'];
}
?>

    

The expression (expr1) ? (expr2) : (expr3) evaluates to <expr2> if <expr1> evaluates to ENTITY, and <expr3> if <expr1> evaluates to ENTITY.

It is possible to leave out the middle part of the ternary operator. Expression expr1 ?: expr3 evaluates to the result of <expr1> if <expr1> evaluates to ENTITY, and <expr3> otherwise. <expr1> is only evaluated once in this case.

[!NOTE] Please note that the ternary operator is an expression, and that it doesn't evaluate to a variable, but to the result of an expression. This is important to know if you want to return a variable by reference. The statement return $var == 42 ? $a : $b; in a return-by-reference function will therefore not work and a warning is issued.

[!NOTE] It is recommended to avoid "stacking" ternary expressions. PHP's behaviour when using more than one unparenthesized ternary operator within a single expression is non-obvious compared to other languages. Indeed prior to PHP 8.0.0, ternary expressions were evaluated left-associative, instead of right-associative like most other programming languages. Relying on left-associativity is deprecated as of PHP 7.4.0. As of PHP 8.0.0, the ternary operator is non-associative.

Non-obvious Ternary Behaviour

<?php
// on first glance, the following appears to output 'true'
echo (true ? 'true' : false ? 't' : 'f');

// however, the actual output of the above is 't' prior to PHP 8.0.0
// this is because ternary expressions are left-associative

// the following is a more obvious version of the same code as above
echo ((true ? 'true' : false) ? 't' : 'f');

// here, one can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool) true, thus returning the true branch of the
// second ternary expression.
?>

     

[!NOTE] Chaining of short-ternaries (?:), however, is stable and behaves reasonably. It will evaluate to the first argument that evaluates to a non-falsy value. Note that undefined values will still raise a warning.

Short-ternary chaining

<?php
echo 0 ?: 1 ?: 2 ?: 3, PHP_EOL; //1
echo 0 ?: 0 ?: 2 ?: 3, PHP_EOL; //2
echo 0 ?: 0 ?: 0 ?: 3, PHP_EOL; //3
?>

     

Null Coalescing Operator

Another useful shorthand operator is the "??" (or null coalescing) operator.

Assigning a default value

<?php
// Example usage for: Null Coalesce Operator
$action = $_POST['action'] ?? 'default';

// The above is identical to this if/else statement
if (isset($_POST['action'])) {
    $action = $_POST['action'];
} else {
    $action = 'default';
}
?>

    

The expression (expr1) ?? (expr2) evaluates to <expr2> if <expr1> is ENTITY, and <expr1> otherwise.

In particular, this operator does not emit a notice or warning if the left-hand side value does not exist, just like isset. This is especially useful on array keys.

[!NOTE] Please note that the null coalescing operator is an expression, and that it doesn't evaluate to a variable, but to the result of an expression. This is important to know if you want to return a variable by reference. The statement return $foo ?? $bar; in a return-by-reference function will therefore not work and a warning is issued.

[!NOTE] The null coalescing operator has low precedence. That means if mixing it with other operators (such as string concatenation or arithmetic operators) parentheses will likely be required.

<?php
// Raises a warning that $name is undefined.
print 'Mr. ' . $name ?? 'Anonymous';

// Prints "Mr. Anonymous"
print 'Mr. ' . ($name ?? 'Anonymous');
?>

   

[!NOTE] Please note that the null coalescing operator allows for simple nesting:

Nesting null coalescing operator

<?php

$foo = null;
$bar = null;
$baz = 1;
$qux = 2;

echo $foo ?? $bar ?? $baz ?? $qux; // outputs 1

?>

     

Error Control Operators

PHP supports one error control operator: the at sign (@). When prepended to an expression in PHP, any diagnostic error that might be generated by that expression will be suppressed.

If a custom error handler function is set with set_error_handler, it will still be called even though the diagnostic has been suppressed.

[!WARNING] Prior to PHP 8.0.0, the error_reporting called inside the custom error handler always returned 0 if the error was suppressed by the @ operator. As of PHP 8.0.0, it returns the value of this (bitwise) expression: E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE.

Any error message generated by the expression is available in the "message" element of the array returned by error_get_last. The result of that function will change on each error, so it needs to be checked early.

Intentional file error

<?php
$my_file = @file ('non_existent_file') or
    die ("Failed opening file: error was '" . error_get_last()['message'] . "'");
?>

   

Suppressing Expressions

<?php
// this works for any expression, not just functions:
$value = @$cache[$key];
// will not issue a notice if the index $key doesn't exist.
?>

   

[!NOTE] The @-operator works only on expressions. A simple rule of thumb is: if one can take the value of something, then one can prepend the @ operator to it. For instance, it can be prepended to variables, functions calls, certain language construct calls (e.g. include), and so forth. It cannot be prepended to function or class definitions, or conditional structures such as if and ENTITY, and so forth.

[!WARNING] Prior to PHP 8.0.0, it was possible for the @ operator to disable critical errors that will terminate script execution. For example, prepending @ to a call of a function which did not exist, by being unavailable or mistyped, would cause the script to terminate with no indication as to why.

ENTITY

error_reporting, Error Handling and Logging functions

Execution Operators

PHP supports one execution operator: backticks (``). Note that these are not single-quotes! PHP will attempt to execute the contents of the backticks as a shell command; the output will be returned (i.e., it won't simply be dumped to output; it can be assigned to a variable). Use of the backtick operator is identical to shell_exec.

Backtick Operator

<?php
$output = `ls -al`;
echo "<pre>$output</pre>";
?>

   

[!NOTE] The backtick operator is disabled when shell_exec is disabled.

[!NOTE] Unlike some other languages, backticks have no special meaning within double-quoted strings.

ENTITY

ENTITY ENTITY
8.5.0 The backtick operator as an alias for shell_exec has been deprecated.

ENTITY

Program Execution functions, popen, proc_open, Using PHP from the commandline

Functional Operators

PHP 8.5 and later supports one operator that works directly on callables. The |ENTITY operator, or “pipe,” accepts a single-parameter callable on the right and passes the left-side value to it, evaluating to the callable's result. The callable on the right may be any valid PHP callable: a Closure, a first-class callable, an object that implements __invoke(), etc.

That means the following two lines are logically equivalent.

Using |ENTITY

<?php
$result = "Hello World" |> strlen(...);
echo $result, PHP_EOL;

$result = strlen("Hello World");
echo $result, PHP_EOL;
?>

   

ENTITY

11
11

For a single call that is not especially useful. It becomes useful when multiple calls are chained together. That is, the following two code fragments are logically equivalent:

Chaining |ENTITY calls

<?php
$result = "PHP Rocks"
    |> htmlentities(...)
    |> str_split(...)
    |> (fn($x) => array_map(strtoupper(...), $x))
    |> (fn($x) => array_filter($x, fn($v) => $v != 'O'))
;
print_r($result);

$temp = "PHP Rocks";
$temp = htmlentities($temp);
$temp = str_split($temp);
$temp = array_map(strtoupper(...), $temp);
$temp = array_filter($temp, fn($v) => $v != 'O');
$result = $temp;
print_r($result);
?>

   

ENTITY

Array
(
    [0] => P
    [1] => H
    [2] => P
    [3] =>
    [4] => R
    [6] => C
    [7] => K
    [8] => S
)
Array
(
    [0] => P
    [1] => H
    [2] => P
    [3] =>
    [4] => R
    [6] => C
    [7] => K
    [8] => S
)

The left-hand side of the pipe may be any value or expression. The right-hand side may be any valid PHP callable that takes a single parameter, or any expression that evaluates to such a callable. Functions with more than one required parameter are not allowed and will fail as if the function were called normally with insufficient arguments. Functions that take a variable by reference are not allowed. If the right-hand side does not evaluate to a valid callable it will throw an Error.

[!NOTE] Be aware that, to avoid syntax ambiguity, arrow functions MUST be wrapped in parentheses when used with a pipe operator, as in the examples above. Failing to do so will result in a fatal error.

ENTITY

Closure

Incrementing/Decrementing Operators

PHP supports pre- and post-increment and decrement operators. Those unary operators allow to increment or decrement the value by one.

Example Name Effect
++$a Pre-increment Increments $a by one, then returns $a.
$a++ Post-increment Returns $a, then increments $a by one.
--$a Pre-decrement Decrements $a by one, then returns $a.
$a-- Post-decrement Returns $a, then decrements $a by one.

Increment/decrement Operators

Examples of Increment/Decrement

<?php
echo 'Post-increment:', PHP_EOL;
$a = 5;
var_dump($a++);
var_dump($a);

echo 'Pre-increment:', PHP_EOL;
$a = 5;
var_dump(++$a);
var_dump($a);

echo 'Post-decrement:', PHP_EOL;
$a = 5;
var_dump($a--);
var_dump($a);

echo 'Pre-decrement:', PHP_EOL;
$a = 5;
var_dump(--$a);
var_dump($a);
?>

   

ENTITY

Post-increment:
int(5)
int(6)
Pre-increment:
int(6)
int(6)
Post-decrement:
int(5)
int(4)
Pre-decrement:
int(4)
int(4)

[!WARNING] The increment and decrement operators have no effect on values of type bool. A E_WARNING is emitted as of PHP 8.3.0, because this will implicitly cast the value to int in the future.

The decrement operator has no effect on values of type null. A E_WARNING is emitted as of PHP 8.3.0, because this will implicitly cast the value to int in the future.

The decrement operator has no effect on non- numeric string, except the empty string, which becomes -1. A E_DEPRECATED is emitted as of PHP 8.3.0, because a TypeError will be thrown in the future.

[!NOTE] Internal objects that support overloading addition and/or subtraction can also be incremented and/or decremented. One such internal object is GMP.

PERL string increment feature

[!WARNING] This feature is soft-deprecated as of PHP 8.3.0. The str_increment function should be used instead. As of PHP 8.5.0, incrementing non-numeric strings emits a deprecation warning.

It is possible to increment a non- numeric string in PHP. The string must be an alphanumerical ASCII string. Which increments letters up to the next letter, when reaching the letter Z the increment is carried to the value on the left. For example, $a = 'Z'; $a++; turns $a into 'AA'.

As of PHP 8.3.0, incrementing empty or non-alphanumeric strings emits E_DEPRECATED. As of PHP 8.5.0, this applies to all non-numeric strings.

PERL string increment example

<?php
echo '== Alphabetic strings ==' . PHP_EOL;
$s = 'W';
for ($n=0; $n<6; $n++) {
    echo ++$s . PHP_EOL;
}
// Alphanumeric strings behave differently
echo '== Alphanumeric strings ==' . PHP_EOL;
$d = 'A8';
for ($n=0; $n<6; $n++) {
    echo ++$d . PHP_EOL;
}
$d = 'A08';
for ($n=0; $n<6; $n++) {
    echo ++$d . PHP_EOL;
}
?>

   

ENTITY

== Alphabetic strings ==
X
Y
Z
AA
AB
AC
== Alphanumeric strings ==
A9
B0
B1
B2
B3
B4
A09
A10
A11
A12
A13
A14

[!WARNING] If the alphanumerical string can be interpreted as a numeric string it will be cast to an int or float. This is particularly an issue with strings that look like a floating point numbers written in exponential notation. The str_increment function does not suffer from these implicit type cast.

Alphanumerical string converted to float

<?php
$s = "5d9";
var_dump(++$s);
var_dump(++$s);
?>

    

ENTITY

string(3) "5e0"
float(6)

This is because the value "5e0" is interpreted as a float and cast to the value 5.0 before being incremented.

Logical Operators

Example Name Result
$a and $b And ENTITY if both $a and $b are ENTITY.
$a or $b Or ENTITY if either $a or $b is ENTITY.
$a xor $b Xor ENTITY if either $a or $b is ENTITY, but not both.
! $a Not ENTITY if $a is not ENTITY.
$a ENTITYENTITY $b And ENTITY if both $a and $b are ENTITY.
$a || $b Or ENTITY if either $a or $b is ENTITY.

Logical Operators

The reason for the two different variations of "and" and "or" operators is that they operate at different precedences. (See Operator Precedence.)

Logical operators illustrated

<?php

// --------------------
// foo() will never get called as those operators are short-circuit

$a = (false && foo());
$b = (true  || foo());
$c = (false and foo());
$d = (true  or  foo());

// --------------------
// "||" has a greater precedence than "or"

// The result of the expression (false || true) is assigned to $e
// Acts like: ($e = (false || true))
$e = false || true;

// The constant false is assigned to $f before the "or" operation occurs
// Acts like: (($f = false) or true)
$f = false or true;

var_dump($e, $f);

// --------------------
// "&&" has a greater precedence than "and"

// The result of the expression (true && false) is assigned to $g
// Acts like: ($g = (true && false))
$g = true && false;

// The constant true is assigned to $h before the "and" operation occurs
// Acts like: (($h = true) and false)
$h = true and false;

var_dump($g, $h);
?>

  

ENTITY

bool(true)
bool(false)
bool(false)
bool(true)

Operator Precedence

The precedence of an operator specifies how "tightly" it binds two expressions together. For example, in the expression 1 + 5 * 3, the answer is 16 and not 18 because the multiplication ("*") operator has a higher precedence than the addition ("+") operator. Parentheses may be used to force precedence, if necessary. For instance: (1 + 5) * 3 evaluates to 18.

When operators have equal precedence their associativity decides how the operators are grouped. For example "-" is left-associative, so 1 - 2 - 3 is grouped as (1 - 2) - 3 and evaluates to -4. "=" on the other hand is right-associative, so $a = $b = $c is grouped as $a = ($b = $c).

Operators of equal precedence that are non-associative cannot be used next to each other, for example 1 ENTITY 2 ENTITY 1 is illegal in PHP. The expression 1 ENTITY= 1 == 1 on the other hand is legal, because the == operator has a lower precedence than the ENTITY= operator.

Associativity is only meaningful for binary (and ternary) operators. Unary operators are either prefix or postfix so this notion is not applicable. For example !!$a can only be grouped as !(!$a).

Use of parentheses, even when not strictly necessary, can often increase readability of the code by making grouping explicit rather than relying on the implicit operator precedence and associativity.

The following table lists the operators in order of precedence, with the highest-precedence ones at the top. Operators on the same line have equal precedence, in which case associativity decides grouping.

Associativity Operators Additional Information
(n/a) clone new clone and new
right ** arithmetic
(n/a) + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ arithmetic (unary + and -), increment/decrement, bitwise, type castingENTITY error control
left instanceof type
(n/a) ! logical
left * / % arithmetic
left + - . arithmetic (binary + and -), arrayENTITY string (. prior to PHP 8.0.0)
left ENTITYENTITY ENTITYENTITY bitwise
left . string (as of PHP 8.0.0)
left ` ENTITY`
non-associative ENTITY ENTITY= ENTITY ENTITY= comparison
non-associative == != === !== ENTITYENTITY ENTITY=ENTITY comparison
left ENTITY bitwiseENTITY references
left ^ bitwise
left ` `
left ENTITYENTITY logical
left `
right ?? null coalescing
non-associative ? : ternary (left-associative prior to PHP 8.0.0)
right = += -= *= **= /= .= %= ENTITY= ` = ^= ENTITYENTITY= ENTITYENTITY= ??=`
(n/a) yield from yield from
(n/a) =ENTITY yield with keys
(n/a) yield yield
(n/a) print print
left and logical
left xor logical
left or logical
(n/a) include include_once require require_once include, include_once, requireENTITY require_once
(n/a) fn (...) =ENTITY fn arrow disambiguity
(n/a) throw throw

Operator Precedence

[!NOTE] The unary operators sharing the row with the cast operators (~, @, and unary +/-) bind more tightly than instanceof, whereas ! binds less tightly. Consequently (int) $x instanceof Foo is grouped as ((int) $x) instanceof Foo, while !$x instanceof Foo is grouped as !($x instanceof Foo).

Associativity

<?php
$a = 3 * 3 % 5; // (3 * 3) % 5 = 4
var_dump($a);

$a = 1;
$b = 2;
$a = $b += 3; // $a = ($b += 3) -> $a = 5, $b = 5
var_dump($a, $b);
?>

   

The ternary operator specifically requires the use of parenthesis to disambiguate precedence.

Explicit Precedence

<?php
$a = true ? 0 : (true ? 1 : 2);
var_dump($a);

// this is not allowed since PHP 8
// $a = true ? 0 : true ? 1 : 2;
?>

   

Operator precedence and associativity only determine how expressions are grouped, they do not specify an order of evaluation. PHP does not (in the general case) specify in which order an expression is evaluated and code that assumes a specific order of evaluation should be avoided, because the behavior can change between versions of PHP or depending on the surrounding code.

Undefined order of evaluation

<?php
$a = 1;
echo $a + $a++; // may print either 2 or 3

$i = 1;
$array[$i] = $i++; // may set either index 1 or 2
?>

   

+, - and . precedence

<?php
$x = 4;
// this line might result in unexpected output:
echo "x minus one equals " . $x-1 . ", or so I hope\n";

// the desired precedence can be enforced by using parentheses:
echo "x minus one equals " . ($x-1) . ", or so I hope\n";

// this is not allowed, and throws a TypeError:
echo (("x minus one equals " . $x) - 1) . ", or so I hope\n";
?>

   

ENTITY

-1, or so I hope
-1, or so I hope
Fatal error: Uncaught TypeError: Unsupported operand types: string - int

Prior to PHP 8, +, - and . had the same precedence

<?php
$x = 4;
// this line might result in unexpected output:
echo "x minus one equals " . $x-1 . ", or so I hope\n";

// because it is evaluated like this line (prior to PHP 8.0.0):
echo (("x minus one equals " . $x) - 1) . ", or so I hope\n";

// the desired precedence can be enforced by using parentheses:
echo "x minus one equals " . ($x-1) . ", or so I hope\n";
?>

   

ENTITY

-1, or so I hope
-1, or so I hope
x minus one equals 3, or so I hope

[!NOTE] Although = has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.

This is possible because the left-hand side of an assignment must be a variable, so the assignment is grouped with that variable rather than with the surrounding higher-precedence prefix operator. The same applies to the other prefix operators that take an expression operand, such as clone, the cast operators, @ and ~: for instance clone $a = $b is grouped as clone ($a = $b), not (clone $a) = $b.

ENTITY

ENTITY ENTITY
8.0.0 String concatenation (.) now has a lower precedence than arithmetic addition/subtraction (+ and -) and bitwise shift left/right (ENTITYENTITY and ENTITYENTITY); previously it had the same precedence as + and - and a higher precedence than ENTITYENTITY and ENTITYENTITY.
8.0.0 The ternary operator (? :) is non-associative now; previously it was left-associative.
7.4.0 Relying on the precedence of string concatenation (.) relative to arithmetic addition/subtraction (+ or -) or bitwise shift left/right (ENTITYENTITY or ENTITYENTITY), i.e. using them together in an unparenthesized expression, is deprecated.
7.4.0 Relying on left-associativity of the ternary operator (? :), i.e. nesting multiple unparenthesized ternary operators, is deprecated.

String Operators

There are two string operators. The first is the concatenation operator ('.'), which returns the concatenation of its right and left arguments. The second is the concatenating assignment operator ('.='), which appends the argument on the right side to the argument on the left side. Please read Assignment Operators for more information.

String Concatenating

<?php
$a = "Hello ";
$b = $a . "World!"; // now $b contains "Hello World!"
var_dump($b);

$a = "Hello ";
$a .= "World!";     // now $a contains "Hello World!"
var_dump($a);
?>

   

ENTITY

String type, String functions

Type Operators

instanceof is used to determine whether a PHP variable is an instantiated object of a certain class:

Using instanceof with classes

<?php
class MyClass
{
}

class NotMyClass
{
}
$a = new MyClass;

var_dump($a instanceof MyClass);
var_dump($a instanceof NotMyClass);
?>

   

ENTITY

bool(true)
bool(false)

instanceof can also be used to determine whether a variable is an instantiated object of a class that inherits from a parent class:

Using instanceof with inherited classes

<?php
class ParentClass
{
}

class MyClass extends ParentClass
{
}

$a = new MyClass;

var_dump($a instanceof MyClass);
var_dump($a instanceof ParentClass);
?>

   

ENTITY

bool(true)
bool(true)

To check if an object is not an instanceof a class, the logical not operator can be used.

Using instanceof to check if object is not an instanceof a class

<?php
class MyClass
{
}

$a = new MyClass;
var_dump(!($a instanceof stdClass));
?>

   

ENTITY

bool(true)

Lastly, instanceof can also be used to determine whether a variable is an instantiated object of a class that implements an interface:

Using instanceof with interfaces

<?php
interface MyInterface
{
}

class MyClass implements MyInterface
{
}

$a = new MyClass;

var_dump($a instanceof MyClass);
var_dump($a instanceof MyInterface);
?>

   

ENTITY

bool(true)
bool(true)

Although instanceof is usually used with a literal classname, it can also be used with another object or a string variable:

Using instanceof with other variables

<?php
interface MyInterface
{
}

class MyClass implements MyInterface
{
}

$a = new MyClass;
$b = new MyClass;
$c = 'MyClass';
$d = 'NotMyClass';

var_dump($a instanceof $b); // $b is an object of class MyClass
var_dump($a instanceof $c); // $c is a string 'MyClass'
var_dump($a instanceof $d); // $d is a string 'NotMyClass'
?>

   

ENTITY

bool(true)
bool(true)
bool(false)

instanceof does not throw any error if the variable being tested is not an object, it simply returns ENTITY. Constants, however, were not allowed prior to PHP 7.3.0.

Using instanceof to test other variables

<?php
$a = 1;
$b = NULL;
$c = fopen('/tmp/', 'r');
var_dump($a instanceof stdClass); // $a is an integer
var_dump($b instanceof stdClass); // $b is NULL
var_dump($c instanceof stdClass); // $c is a resource
var_dump(FALSE instanceof stdClass);
?>

   

ENTITY

bool(false)
bool(false)
bool(false)
PHP Fatal error:  instanceof expects an object instance, constant given

As of PHP 7.3.0, constants are allowed on the left-hand-side of the instanceof operator.

Using instanceof to test constants

<?php
var_dump(FALSE instanceof stdClass);
?>

   

ENTITY

bool(false)

As of PHP 8.0.0, instanceof can now be used with arbitrary expressions. The expression must be wrapped in parentheses and produce a string.

Using instanceof with an arbitrary expression

<?php

class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}

function getSomeClass(): string
{
    return ClassA::class;
}

var_dump(new ClassA instanceof ('std' . 'Class'));
var_dump(new ClassB instanceof ('Class' . 'B'));
var_dump(new ClassC instanceof ('Class' . 'A'));
var_dump(new ClassD instanceof (getSomeClass()));
?>

   

ENTITY

bool(true)
bool(true)
bool(false)
bool(true)

The instanceof operator has a functional variant with the is_a function.

ENTITY

get_class, is_a

construct

AllowDynamicProperties::__construct

Construct a new AllowDynamicProperties attribute instance

ENTITY

public

AllowDynamicProperties::__construct

Constructs a new AllowDynamicProperties instance.

ENTITY ENTITY

argumentcounterror

ENTITY

ArgumentCountError is thrown when too few arguments are passed to a user-defined function or method.

This error is also thrown when too many arguments are passed to a non-variadic built-in function.

ENTITY

ArgumentCountError

extends

TypeError

ENTITY

ENTITY

arithmeticerror

ENTITY

ArithmeticError is thrown when an error occurs while performing mathematical operations. These errors include attempting to perform a bitshift by a negative amount, and any call to intdiv that would result in a value outside the possible bounds of an int.

ENTITY

ArithmeticError

extends

Error

ENTITY

ENTITY

arrayaccess

ENTITY

Interface to provide access to objects as arrays.

ENTITY

ArrayAccess

ENTITY

ENTITY

Basic usage

<?php
class Obj implements ArrayAccess {
    public $container = [
        "one"   => 1,
        "two"   => 2,
        "three" => 3,
    ];

    public function offsetSet($offset, $value): void {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset): bool {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset): void {
        unset($this->container[$offset]);
    }

    public function offsetGet($offset): mixed {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
}

$obj = new Obj;

var_dump(isset($obj["two"]));
var_dump($obj["two"]);
unset($obj["two"]);
var_dump(isset($obj["two"]));
$obj["two"] = "A value";
var_dump($obj["two"]);
$obj[] = 'Append 1';
$obj[] = 'Append 2';
$obj[] = 'Append 3';
print_r($obj);

    

ENTITY

bool(true)
int(2)
bool(false)
string(7) "A value"
Obj Object
(
    [container] => Array
        (
            [one] => 1
            [three] => 3
            [two] => A value
            [0] => Append 1
            [1] => Append 2
            [2] => Append 3
        )

)

ENTITY ENTITY ENTITY ENTITY

offsetexists

ArrayAccess::offsetExists

Whether an offset exists

ENTITY

public

bool

ArrayAccess::offsetExists

mixed

offset

Whether or not an offset exists.

This method is executed when using isset or empty on objects implementing ArrayAccess.

[!NOTE] When using empty ArrayAccess::offsetGet will be called and checked if empty only if ArrayAccess::offsetExists returns ENTITY.

ENTITY

offset
An offset to check for.

ENTITY

ENTITY

[!NOTE] The return value will be casted to bool if non-boolean was returned.

ENTITY

ArrayAccess::offsetExists example

<?php
class obj implements ArrayAccess {
    public function offsetSet($offset, $value): void {
        var_dump(__METHOD__);
    }
    public function offsetExists($var): bool {
        var_dump(__METHOD__);
        if ($var == "foobar") {
            return true;
        }
        return false;
    }
    public function offsetUnset($var): void {
        var_dump(__METHOD__);
    }
    #[\ReturnTypeWillChange]
    public function offsetGet($var) {
        var_dump(__METHOD__);
        return "value";
    }
}

$obj = new obj;

echo "Runs obj::offsetExists()\n";
var_dump(isset($obj["foobar"]));

echo "\nRuns obj::offsetExists() and obj::offsetGet()\n";
var_dump(empty($obj["foobar"]));

echo "\nRuns obj::offsetExists(), *not* obj:offsetGet() as there is nothing to get\n";
var_dump(empty($obj["foobaz"]));
?>

    

ENTITY

Runs obj::offsetExists()
string(17) "obj::offsetExists"
bool(true)

Runs obj::offsetExists() and obj::offsetGet()
string(17) "obj::offsetExists"
string(14) "obj::offsetGet"
bool(false)

Runs obj::offsetExists(), *not* obj:offsetGet() as there is nothing to get
string(17) "obj::offsetExists"
bool(true)

offsetget

ArrayAccess::offsetGet

Offset to retrieve

ENTITY

public

mixed

ArrayAccess::offsetGet

mixed

offset

Returns the value at specified offset.

This method is executed when checking if offset is empty.

ENTITY

offset
The offset to retrieve.

ENTITY

Can return all value types.

ENTITY

[!NOTE] It's possible for implementations of this method to return by reference. This makes indirect modifications to the overloaded array dimensions of ArrayAccess objects possible.

A direct modification is one that replaces completely the value of the array dimension, as in $obj[6] = 7. An indirect modification, on the other hand, only changes part of the dimension, or attempts to assign the dimension by reference to another variable, as in $obj[6][7] = 7 or $var =ENTITY $obj[6]. Increments with ++ and decrements with -- are also implemented in a way that requires indirect modification.

While direct modification triggers a call to ArrayAccess::offsetSet, indirect modification triggers a call to ArrayAccess::offsetGet. In that case, the implementation of ArrayAccess::offsetGet must be able to return by reference, otherwise an E_NOTICE message is raised.

ENTITY

ArrayAccess::offsetExists

offsetset

ArrayAccess::offsetSet

Assign a value to the specified offset

ENTITY

public

void

ArrayAccess::offsetSet

mixed

offset

mixed

value

Assigns a value to the specified offset.

ENTITY

offset
The offset to assign the value to.

value
The value to set.

ENTITY

ENTITY

ENTITY

[!NOTE] The offset parameter will be set to ENTITY if another value is not available, like in the following example.

<?php
$arrayaccess[] = "first value";
$arrayaccess[] = "second value";
print_r($arrayaccess);
?>

     

ENTITY

Array
(
    [0] => first value
    [1] => second value
)

[!NOTE] This function is not called in assignments by reference and otherwise indirect changes to array dimensions overloaded with ArrayAccess (indirect in the sense they are made not by changing the dimension directly, but by changing a sub-dimension or sub-property or assigning the array dimension by reference to another variable). Instead, ArrayAccess::offsetGet is called. The operation will only be successful if that method returns by reference.

offsetunset

ArrayAccess::offsetUnset

Unset an offset

ENTITY

public

void

ArrayAccess::offsetUnset

mixed

offset

Unsets an offset.

[!NOTE] This method will not be called when type-casting to (unset)

ENTITY

offset
The offset to unset.

ENTITY

ENTITY

assertionerror

ENTITY

AssertionError is thrown when an assertion made via assert fails.

ENTITY

AssertionError

extends

Error

ENTITY

ENTITY

construct

Attribute::__construct

Construct a new Attribute instance

ENTITY

public

Attribute::__construct

int

flags

Attribute::TARGET_ALL

Constructs a new Attribute instance.

ENTITY

flags

Predefined Attributes

PHP provides some predefined attributes that can be used.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

allowdynamicproperties

ENTITY

This attribute is used to mark classes that allow dynamic properties.

[!NOTE] Although attributes themselves are not inherited, the effect of the AllowDynamicProperties attribute is inherited. Child classes of a class marked with this attribute will also allow dynamic properties, even if they do not explicitly declare the attribute.

[!NOTE] This attribute was introduced in PHP 8.2.0 as the explicit way to allow dynamic properties. Creating a dynamic property on a class that does not use this attribute, and that does not implement __get() or __set(), is deprecated.

ENTITY

#[\Attribute(\Attribute::TARGET_CLASS)]

final

AllowDynamicProperties

ENTITY

ENTITY

AllowDynamicProperties with a dynamic property

To enable dynamic properties, add #[\AllowDynamicProperties].

<?php
#[\AllowDynamicProperties]
class ValidExample { }

$obj = new ValidExample();
$obj->myDynamicProp = 1234;
?>

    

AllowDynamicProperties with non-existing property

As of PHP 8.2.0, the declaration is required unless the class uses this attribute. Creating an undeclared property on such a class emits a deprecation notice.

<?php
class InvalidExample { }

$obj = new InvalidExample();
$obj->myUnknownProperty = 1234;
?>

    

ENTITY

Deprecated: Creation of dynamic property InvalidExample::$myUnknownProperty is deprecated in file on line 5

AllowDynamicProperties with non-existing property in inherited class

     
<?php
class DefaultBehaviour { }

#[\AllowDynamicProperties]
class ClassAllowsDynamicProperties { }

class InheritedClassAllowsDynamicProperties extends ClassAllowsDynamicProperties { }

$o1 = new DefaultBehaviour();
$o2 = new InheritedClassAllowsDynamicProperties();

$o1->nonExistingProp = true;
$o2->nonExistingProp = true;
?>

    

ENTITY

Deprecated: Creation of dynamic property DefaultBehaviour::$nonExistingProp is deprecated in file on line 12

ENTITY

Attributes overview

ENTITY

attribute

ENTITY

Attributes offer the ability to add structured, machine-readable metadata information on declarations in code: Classes, methods, functions, parameters, properties and class constants can be the target of an attribute. The metadata defined by attributes can then be inspected at runtime using the Reflection APIs. Attributes could therefore be thought of as a configuration language embedded directly into code.

ENTITY

#[\Attribute(\Attribute::TARGET_CLASS)]

final

Attribute

ENTITY

const

int

Attribute::TARGET_CLASS

const

int

Attribute::TARGET_FUNCTION

const

int

Attribute::TARGET_METHOD

const

int

Attribute::TARGET_PROPERTY

const

int

Attribute::TARGET_CLASS_CONSTANT

const

int

Attribute::TARGET_PARAMETER

const

int

Attribute::TARGET_CONSTANT

const

int

Attribute::TARGET_ALL

const

int

Attribute::IS_REPEATABLE

ENTITY

public

int

flags

ENTITY

ENTITY

Attribute::TARGET_CLASS

Attribute::TARGET_FUNCTION

Attribute::TARGET_METHOD

Attribute::TARGET_PROPERTY

Attribute::TARGET_CLASS_CONSTANT

Attribute::TARGET_PARAMETER

Attribute::TARGET_CONSTANT

Attribute::TARGET_ALL

Attribute::IS_REPEATABLE

ENTITY

flags

ENTITY

ENTITY ENTITY
8.5.0 Added Attribute::TARGET_CONSTANT. Applying #[\Attribute] to an abstract class, enum, interface, or trait now triggers a compile-time error (previously it was only reported at runtime when ReflectionAttribute::newInstance was called).

ENTITY

Attributes overview

ENTITY

delayedtargetvalidation

ENTITY

This attribute delays target validation errors for internal attributes from compile time to when the attribute is instantiated via the Reflection API.

When applied to a declaration, any invalid usage of internal attributes on the same target will not trigger a compile time error. Instead, the validation is deferred and performed when the attribute is instantiated via ReflectionAttribute::newInstance().

This is primarily intended for forward compatibility, allowing code to use attributes that may gain additional valid targets in future PHP versions without breaking on older versions.

ENTITY

#[\Attribute(\Attribute::TARGET_ALL)]

final

DelayedTargetValidation

ENTITY

Delaying validation of an invalid target

<?php

class Base {
    protected function foo(): void {}
}

class Child extends Base {

    #[\DelayedTargetValidation]
    #[\Override]
    public const NAME = 'child';

    #[\Override]
    protected function foo(): void {}
}

On PHP versions where Override is not allowed on class constants, this does not produce a compile time error.

Validation occurs during reflection

<?php

$reflection = new ReflectionClassConstant(Child::class, 'NAME');

foreach ($reflection->getAttributes() as $attribute) {
    $attribute->newInstance(); // May throw if invalid
}

When any attribute applied to the same target (other than DelayedTargetValidation itself) is instantiated via reflection using ReflectionAttribute::newInstance(), target validation is performed and an exception may be thrown if the attribute is used on an unsupported target.

ENTITY

This attribute only affects target validation of internal attributes.

It does not suppress functional validation performed by those attributes. For example, Override will still emit an error if a method does not actually override a parent method.

ENTITY

Attributes overview

Override

deprecated

ENTITY

This attribute is used to mark functionality as deprecated. Using deprecated functionality will cause an E_USER_DEPRECATED error to be emitted.

As of PHP 8.5.0, this attribute can also be applied to traits and to compile-time constants declared outside of a class.

ENTITY

#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::TARGET_CLASS_CONSTANT | \Attribute::TARGET_CONSTANT | \Attribute::TARGET_CLASS)]

final

Deprecated

ENTITY

public

readonly

string

null

message

public

readonly

string

null

since

ENTITY

ENTITY

message
An optional message explaining the reason for the deprecation and possible replacement functionality. Will be included in the emitted deprecation message.

since
An optional string indicating since when the functionality is deprecated. The contents are not validated by PHP and may contain a version number, a date or any other value that is considered appropriate. Will be included in the emitted deprecation message.

Functionality that is part of PHP will use Major.Minor as the since value, for example '8.4'.

ENTITY

<?php

#[\Deprecated(message: "use safe_replacement() instead", since: "1.5")]
function unsafe_function()
{
   echo "This is unsafe", PHP_EOL;
}

unsafe_function();

?>

    

ENTITY

Deprecated: Function unsafe_function() is deprecated since 1.5, use safe_replacement() instead in example.php on line 9
This is unsafe

ENTITY

ENTITY ENTITY
8.5.0 Deprecated can now be applied to traits and to compile-time constants declared outside of a class, the latter through the new Attribute::TARGET_CONSTANT target.

ENTITY

Attributes overview

ReflectionFunctionAbstract::isDeprecated

ReflectionClassConstant::isDeprecated

E_USER_DEPRECATED

ENTITY

construct

Deprecated::__construct

Construct a new Deprecated attribute instance

ENTITY

public

Deprecated::__construct

string

null

message

ENTITY

string

null

since

ENTITY

Constructs a new Deprecated instance.

ENTITY

message
The value of the message property.

since
The value of the since property.

nodiscard

ENTITY

This attribute can be used to indicate that the return value of a function or a method should not be discarded. If the return value is not used in any way, a warning will be emitted.

This is useful for functions where not checking the return value is likely to be a bug.

To intentionally discard the return value of such a function, use (void) cast to suppress the warning.

[!NOTE] Since attributes are designed to be backwards compatible, #[\NoDiscard] can be added to functions and methods even when PHP 8.4 or below are supported, it just won't do anything. On PHP 8.5 and above a warning will be emitted if the result is unused. To suppress the warning without using (void), which is not supported before PHP 8.5, consider using a variable like $_.

[!NOTE] #[\NoDiscard] applies to the specific function or method declaration it is written on, and the warning is emitted based on the declaration that is actually called. As a result, adding #[\NoDiscard] to an interface method or an abstract method does not emit a warning, because the method that is invoked is the implementing or overriding method. Likewise, a method that overrides a #[\NoDiscard] method does not emit the warning unless it is itself marked with the attribute. In contrast, a method imported from a trait keeps the attribute, because the trait method is copied into the using class as if declared there.

ENTITY

#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION)]

final

NoDiscard

ENTITY

public

readonly

string

null

message

ENTITY

ENTITY

message
An optional message explaining why the return value should not be discarded.

ENTITY

Basic usage

<?php

/**
 * Processes all the given items and returns an array with the results of the
 * operation for each item. `null` indicates success and an Exception indicates
 * an error. The keys of the result array match the keys of the $items array.
 *
 * @param array<string> $items
 * @return array<null|Exception>
 */
#[\NoDiscard("as processing might fail for individual items")]
function bulk_process(array $items): array {
    $results = [];

    foreach ($items as $key => $item) {
        if (\random_int(0, 9999) < 9999) {
            // Pretend to do something useful with $item,
            // which will succeed in 99.99% of cases.
            echo "Processing {$item}", PHP_EOL;
            $error = null;
        } else {
            $error = new \Exception("Failed to process {$item}.");
        }

        $results[$key] = $error;
    }

    return $results;
}

bulk_process($items);

?>

    

ENTITY

Warning: The return value of function bulk_process() should either be used or intentionally ignored by casting it as (void), as processing might fail for individual items

Intentionally discarding the return value

<?php

#[\NoDiscard]
function some_command(): int {
    return 1;
}

// Suppress the warning using (void) - PHP 8.5+
(void) some_command();

// For compatibility with PHP versions before 8.5, use a temporary variable
$_ = some_command();

?>

    

ENTITY

Attributes overview

ENTITY

construct

NoDiscard::__construct

Construct a new NoDiscard attribute instance

ENTITY

public

NoDiscard::__construct

string

null

message

ENTITY

Constructs a new NoDiscard instance.

ENTITY

message
The value of the message property.

override

ENTITY

This attribute is used to indicate that a method or a property is intended to override a method or a property of a parent class or that it implements a method or a property defined in an interface.

If no method or property with the same name exists in a parent class or in an implemented interface a compile-time error will be emitted.

The attribute cannot be used on the __construct() method, which is exempt from signature checks.

ENTITY

#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)]

final

Override

ENTITY

ENTITY

ENTITY ENTITY
8.5.0 Override can be applied to properties.

ENTITY

Usage with methods

<?php

class Base {
    protected function foo(): void {}
}

final class Extended extends Base {
    #[\Override]
    protected function boo(): void {}
}

?>

    

ENTITY

Fatal error: Extended::boo() has #[\Override] attribute, but no matching parent method exists

Usage with properties

<?php

class Base {
    protected string $foo;
}

final class Extended extends Base {
    #[\Override]
    protected string $boo;
}

?>

    

ENTITY

Fatal error: Extended::$boo has #[\Override] attribute, but no matching parent property exists

ENTITY

Attributes overview

ENTITY

construct

Override::__construct

Construct a new Override attribute instance

ENTITY

public

Override::__construct

Constructs a new Override instance.

ENTITY ENTITY

returntypewillchange

ENTITY

As of PHP 8.1.0, a tentative phase of transitioning to return type declarations for internal class methods began.

Most non-final internal methods now require overriding methods to declare a compatible return type. Otherwise, a deprecation notice is emitted during inheritance validation warning that the signature violates covariance rules.

In a future PHP version, method signature checking will become strict, and mismatches will cause a fatal error.

In case the return type cannot be declared for an overriding method due to PHP cross-version compatibility concerns, or the overriding method declares an incompatible return type, a #[\ReturnTypeWillChange] attribute can be added to silence the deprecation notice.

[!WARNING] When overriding methods defined in user-defined classes, return types are checked strictly. A fatal error is emitted on mismatch, even if the overriding method is marked with the attribute.

The ReturnTypeWillChange attribute suppresses deprecation warnings only during the tentative return type phase. After strict type checking is enforced, the attribute will stop working and a mismatch in the overriding method signature of an internal class will cause a fatal error.

ENTITY

#[\Attribute(\Attribute::TARGET_METHOD)]

final

ReturnTypeWillChange

ENTITY

ENTITY

Attributes overview

ENTITY

sensitiveparameter

ENTITY

This attribute is used to mark a parameter that is sensitive and should have its value redacted if present in a stack trace.

ENTITY

#[\Attribute(\Attribute::TARGET_PARAMETER)]

final

SensitiveParameter

ENTITY

ENTITY

<?php

function defaultBehavior(
    string $secret,
    string $normal
) {
    throw new Exception('Error!');
}

function sensitiveParametersWithAttribute(
    #[\SensitiveParameter]
    string $secret,
    string $normal
) {
    throw new Exception('Error!');
}

try {
    defaultBehavior('password', 'normal');
} catch (Exception $e) {
    echo $e, PHP_EOL, PHP_EOL;
}

try {
    sensitiveParametersWithAttribute('password', 'normal');
} catch (Exception $e) {
    echo $e, PHP_EOL, PHP_EOL;
}

?>

    

ENTITY

Exception: Error! in example.php:7
Stack trace:
#0 example.php(19): defaultBehavior('password', 'normal')
#1 {main}

Exception: Error! in example.php:15
Stack trace:
#0 example.php(25): sensitiveParametersWithAttribute(Object(SensitiveParameterValue), 'normal')
#1 {main}

ENTITY

Attributes overview, SensitiveParameterValue

ENTITY

backedenum

ENTITY

The BackedEnum interface is automatically applied to backed enumerations by the engine. It may not be implemented by user-defined classes. Enumerations may not override its methods, as default implementations are provided by the engine. It is available only for type checks.

ENTITY

BackedEnum

extends

UnitEnum

ENTITY

ENTITY

ENTITY ENTITY

from

BackedEnum::from

Maps a scalar to an enum instance

ENTITY

public

static

static

BackedEnum::from

int

string

value

The from method translates a string or int into the corresponding Enum case, if any. If there is no matching case defined, it will throw a ValueError.

ENTITY

value
The scalar value to map to an enum case.

ENTITY

A case instance of this enumeration.

ENTITY

Basic usage

The following example illustrates how enum cases are returned.

<?php
enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

$h = Suit::from('H');

var_dump($h);

$b = Suit::from('B');
?>

   

ENTITY

enum(Suit::Hearts)

Fatal error: Uncaught ValueError: "B" is not a valid backing value for enum "Suit" in /file.php:15

ENTITY

UnitEnum::cases, BackedEnum::tryFrom

tryfrom

BackedEnum::tryFrom

Maps a scalar to an enum instance or null

ENTITY

public

static

static

null

BackedEnum::tryFrom

int

string

value

The tryFrom method translates a string or int into the corresponding Enum case, if any. If there is no matching case defined, it will return null.

ENTITY

value
The scalar value to map to an enum case.

ENTITY

A case instance of this enumeration, or null if not found.

ENTITY

Basic usage

The following example illustrates how enum cases are returned.

<?php
enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

$h = Suit::tryFrom('H');

var_dump($h);

$b = Suit::tryFrom('B') ?? Suit::Spades;

var_dump($b);
?>

   

ENTITY

enum(Suit::Hearts)
enum(Suit::Spades)

ENTITY

UnitEnum::cases, BackedEnum::from

closedgeneratorexception

ENTITY

A ClosedGeneratorException is thrown when trying to retrieve a value from a closed Generator.

ENTITY

ClosedGeneratorException

extends

Exception

ENTITY

ENTITY

closure

ENTITY

Class used to represent anonymous functions.

Anonymous functions yield objects of this type. This class has methods that allow further control of the anonymous function after it has been created.

Besides the methods listed here, this class also has an __invoke method. This is for consistency with other classes that implement calling magic, as this method is not used for calling the function.

ENTITY

final

Closure

ENTITY

ENTITY

ENTITY ENTITY
8.4.0 The output of Closure::__debugInfo now includes the name, line, and file of the closure.

ENTITY

[!NOTE] Closure objects cannot be serialized as closures may contain bound variables and a specific execution context. Attempting to serialize a closure will throw an Exception.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

bind

Closure::bind

Duplicates a closure with a specific bound object and class scope

ENTITY

public

static

Closure

null

Closure::bind

Closure

closure

object

null

newThis

object

string

null

newScope

"static"

This method is a static version of Closure::bindTo. See the documentation of that method for more information.

ENTITY

closure
The anonymous functions to bind.

newThis
The object to which the given anonymous function should be bound, or ENTITY for the closure to be unbound.

newScope
The class scope to which the closure is to be associated, or 'static' to keep the current one. If an object is given, the type of the object will be used instead. This determines the visibility of protected and private methods of the bound object. It is not allowed to pass (an object of) an internal class as this parameter.

ENTITY

Returns a new Closure object, or ENTITY on failure.

ENTITY

ENTITY ENTITY
8.5.0 Binding an instance to a static closure, or binding a method from an incompatible class hierarchy, is now deprecated (these cases already emitted an E_WARNING).

ENTITY

Closure::bind example

<?php
class A {
    private static $sfoo = 1;
    private $ifoo = 2;
}
$cl1 = static function() {
    return A::$sfoo;
};
$cl2 = function() {
    return $this->ifoo;
};

$bcl1 = Closure::bind($cl1, null, 'A');
$bcl2 = Closure::bind($cl2, new A(), 'A');
echo $bcl1(), "\n";
echo $bcl2(), "\n";
?>

   

ENTITY

1
2

ENTITY

Anonymous functions

Closure::bindTo

bindto

Closure::bindTo

Duplicates the closure with a new bound object and class scope

ENTITY

public

Closure

null

Closure::bindTo

object

null

newThis

object

string

null

newScope

"static"

Create and return a new anonymous function with the same body and bound variables as this one, but possibly with a different bound object and a new class scope.

The “bound object” determines the value $this will have in the function body and the “class scope” represents a class which determines which private and protected members the anonymous function will be able to access. Namely, the members that will be visible are the same as if the anonymous function were a method of the class given as value of the newScope parameter.

Static closures cannot have any bound object (the value of the parameter newThis should be ENTITY), but this method can nevertheless be used to change their class scope.

This method will ensure that for a non-static closure, having a bound instance will imply being scoped and vice-versa. To this end, non-static closures that are given a scope but a ENTITY instance are made static and non-static non-scoped closures that are given a non-null instance are scoped to an unspecified class.

[!NOTE] If you only want to duplicate the anonymous functions, you can use cloning instead.

ENTITY

newThis
The object to which the given anonymous function should be bound, or ENTITY for the closure to be unbound.

newScope
The class scope to which the closure is to be associated, or 'static' to keep the current one. If an object is given, the type of the object will be used instead. This determines the visibility of protected and private methods of the bound object. It is not allowed to pass (an object of) an internal class as this parameter.

ENTITY

Returns the newly created Closure object or ENTITY on failure.

ENTITY

ENTITY ENTITY
8.5.0 Binding an instance to a static closure, or binding a method from an incompatible class hierarchy, is now deprecated (these cases already emitted an E_WARNING).

ENTITY

Closure::bindTo example

<?php

class A
{
    private $val;

    public function __construct($val)
    {
        $this->val = $val;
    }

    public function getClosure()
    {
        // Returns closure bound to this object and scope
        return function() {
            return $this->val;
        };
    }
}

$ob1 = new A(1);
$ob2 = new A(2);

$cl = $ob1->getClosure();
echo $cl(), "\n";

$cl = $cl->bindTo($ob2);
echo $cl(), "\n";

?>

   

ENTITY

1
2

ENTITY

Anonymous functions

Closure::bind

call

Closure::call

Binds and calls the closure

ENTITY

public

mixed

Closure::call

object

newThis

mixed

args

Temporarily binds the closure to newThis, and calls it with any given parameters.

ENTITY

newThis
The object to bind the closure to for the duration of the call.

args
Zero or more parameters, which will be given as parameters to the closure.

ENTITY

Returns the return value of the closure.

ENTITY

Closure::call example

<?php
class Value {
    protected $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }
}

$three = new Value(3);
$four = new Value(4);

$closure = function ($delta) { var_dump($this->getValue() + $delta); };
$closure->call($three, 4);
$closure->call($four, 4);
?>

   

ENTITY

int(7)
int(8)

construct

Closure::__construct

Constructor that disallows instantiation

ENTITY

private

Closure::__construct

This method exists only to disallow instantiation of the Closure class. Objects of this class are created in the fashion described on the anonymous functions page.

ENTITY ENTITY

ENTITY

Anonymous functions

fromcallable

Closure::fromCallable

Converts a callable into a closure

ENTITY

public

static

Closure

Closure::fromCallable

callable

callback

Create and return a new anonymous function from given callback using the current scope. This method checks if the callback is callable in the current scope and throws a TypeError if it is not.

[!NOTE] As of PHP 8.1.0, First class callable syntax has the same semantics as this method.

ENTITY

callback
The callable to convert.

ENTITY

Returns the newly created Closure or throws a TypeError if the callback is not callable in the current scope.

ENTITY

Anonymous functions

First class callable syntax

getcurrent

Closure::getCurrent

Returns the currently executing closure

ENTITY

public

static

Closure

Closure::getCurrent

Returns the currently executing closure. This method is primarily useful for implementing recursive closures without needing to capture a reference to the closure variable using the use keyword.

This method must be called from within a closure; calling it outside of a closure context will result in Error: Current function is not a closure.

ENTITY ENTITY

ENTITY

Returns the currently executing Closure instance.

ENTITY

Throws an Error if called outside of a closure context.

ENTITY

Closure::getCurrent example

Using Closure::getCurrent to implement a recursive Fibonacci function:

<?php
$fibonacci = function (int $n) {
    if ($n === 0 || $n === 1) {
        return $n;
    }

    $fn = Closure::getCurrent();
    return $fn($n - 1) + $fn($n - 2);
};

echo $fibonacci(10); // Outputs: 55
?>

   

Comparison with traditional approach

Prior to PHP 8.5, implementing recursive closures required capturing a reference to the closure variable using the use keyword:

<?php
// Traditional approach (still works in PHP 8.5)
$fibonacci = function (int $n) use (&$fibonacci) {
    if ($n === 0) return 0;
    if ($n === 1) return 1;
    return $fibonacci($n - 1) + $fibonacci($n - 2);
};

echo $fibonacci(10); // Outputs: 55
?>

   

The Closure::getCurrent approach eliminates the need to declare the variable with a reference in the use clause, making the code cleaner and less error-prone.

compileerror

ENTITY

CompileError is thrown for some compilation errors, which formerly issued a fatal error.

ENTITY

CompileError

extends

Error

ENTITY

ENTITY

countable

ENTITY

Classes implementing Countable can be used with the count function.

ENTITY

Countable

ENTITY

ENTITY

count

Countable::count

Count elements of an object

ENTITY

public

int

Countable::count

This method is executed when the value for count is an object implementing Countable.

ENTITY ENTITY

ENTITY

The custom count as an int.

ENTITY

Countable::count example

<?php

class Counter implements Countable
{
    private $count = 0;

    public function count(): int
    {
        return ++$this->count;
    }
}

$counter = new Counter;

for ($i = 0; $i < 10; ++$i) {
    echo "I have been count()ed " . count($counter) . " times\n";
}

?>

   

ENTITY

I have been count()ed 1 times
I have been count()ed 2 times
I have been count()ed 3 times
I have been count()ed 4 times
I have been count()ed 5 times
I have been count()ed 6 times
I have been count()ed 7 times
I have been count()ed 8 times
I have been count()ed 9 times
I have been count()ed 10 times

divisionbyzeroerror

ENTITY

DivisionByZeroError is thrown when an attempt is made to divide a number by zero.

ENTITY

DivisionByZeroError

extends

ArithmeticError

ENTITY

ENTITY

error

ENTITY

Error is the base class for errors that indicate programming mistakes. Such errors generally require a correction to the program rather than being handled during normal operation.

ENTITY

Error

implements

Throwable

ENTITY

protected

string

message

""

private

string

string

""

protected

int

code

protected

string

file

""

protected

int

line

private

array

trace

[]

private

Throwable

null

previous

null

ENTITY

ENTITY

message
The error message

code
The error code

file
The filename where the error happened

line
The line where the error happened

previous
The previously thrown exception

string
The string representation of the stack trace

trace
The stack trace as an array

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

clone

Error::__clone

Clone the error

ENTITY

private

void

Error::__clone

Errors do not support cloning; this method exists only to prevent it.

[!WARNING] Errors cannot be cloned, whether they are instances of Error or of a subclass. Attempting to clone an error throws an Error, which may be caught.

ENTITY ENTITY

ENTITY

ENTITY

ENTITY

Attempting to clone an error throws an Error with the following message: Trying to clone an uncloneable object of class ClassName.

ENTITY

ENTITY ENTITY
8.1.0 Error::__clone is no longer final.

construct

Error::__construct

Construct the error object

ENTITY

public

Error::__construct

string

message

""

int

code

0

Throwable

null

previous

ENTITY

Constructs the Error.

ENTITY

message
The error message.

code
The error code.

previous
The previous throwable used for the exception chaining.

ENTITY

[!NOTE] The message is NOT binary safe.

getcode

Error::getCode

Gets the error code

ENTITY

final

public

int

Error::getCode

Returns the error code.

ENTITY ENTITY

ENTITY

Returns the error code as int

ENTITY

Error::getCode example

<?php
try {
    throw new Error("Some error message", 30);
} catch(Error $e) {
    echo "The Error code is: " . $e->getCode();
}
?>

    

ENTITY

The Error code is: 30

ENTITY

Throwable::getCode

getfile

Error::getFile

Gets the file in which the error occurred

ENTITY

final

public

string

Error::getFile

Get the name of the file the error occurred.

ENTITY ENTITY

ENTITY

Returns the filename in which the error occurred.

ENTITY

Error::getFile example

<?php
try {
    throw new Error;
} catch(Error $e) {
    echo $e->getFile();
}
?>

    

ENTITY

/home/bjori/tmp/ex.php

ENTITY

Throwable::getFile

getline

Error::getLine

Gets the line in which the error occurred

ENTITY

final

public

int

Error::getLine

Get line number where the error occurred.

ENTITY ENTITY

ENTITY

Returns the line number where the error occurred.

ENTITY

Error::getLine example

<?php
try {
    throw new Error("Some error message");
} catch(Error $e) {
    echo "The error was created on line: " . $e->getLine();
}
?>

    

ENTITY

The error was created on line: 3

ENTITY

Throwable::getLine

getmessage

Error::getMessage

Gets the error message

ENTITY

final

public

string

Error::getMessage

Returns the error message.

ENTITY ENTITY

ENTITY

Returns the error message as a string.

ENTITY

Error::getMessage example

<?php
try {
    throw new Error("Some error message");
} catch(Error $e) {
    echo $e->getMessage();
}
?>

    

ENTITY

Some error message

ENTITY

Throwable::getMessage

getprevious

Error::getPrevious

Returns previous Throwable

ENTITY

final

public

Throwable

null

Error::getPrevious

Returns previous Throwable (the third parameter of Error::__construct).

ENTITY ENTITY

ENTITY

Returns the previous Throwable if available or ENTITY otherwise.

ENTITY

Error::getPrevious example

Looping over, and printing out, error trace.

<?php
class MyCustomError extends Error {}

function doStuff() {
    try {
        throw new TypeError("You are doing it wrong!", 112);
    } catch(Error $e) {
        throw new MyCustomError("Something happened", 911, $e);
    }
}


try {
    doStuff();
} catch(Error $e) {
    do {
        printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e));
    } while($e = $e->getPrevious());
}
?>

    

ENTITY

/home/bjori/ex.php:8 Something happened (911) [MyCustomError]
/home/bjori/ex.php:6 You are doing it wrong! (112) [TypeError]

ENTITY

Throwable::getPrevious

gettrace

Error::getTrace

Gets the stack trace

ENTITY

final

public

array

Error::getTrace

Returns the stack trace.

ENTITY ENTITY

ENTITY

Returns the stack trace as an array.

ENTITY

Error::getTrace example

<?php
function test() {
 throw new Error;
}

try {
 test();
} catch(Error $e) {
 var_dump($e->getTrace());
}
?>

    

ENTITY

array(1) {
  [0]=>
  array(4) {
    ["file"]=>
    string(22) "/home/bjori/tmp/ex.php"
    ["line"]=>
    int(7)
    ["function"]=>
    string(4) "test"
    ["args"]=>
    array(0) {
    }
  }
}

ENTITY

Throwable::getTrace

gettraceasstring

Error::getTraceAsString

Gets the stack trace as a string

ENTITY

final

public

string

Error::getTraceAsString

Returns the stack trace as a string.

ENTITY ENTITY

ENTITY

Returns the stack trace as a string.

ENTITY

Error::getTraceAsString example

<?php
function test() {
    throw new Error;
}

try {
    test();
} catch(Error $e) {
    echo $e->getTraceAsString();
}
?>

    

ENTITY

#0 /home/bjori/tmp/ex.php(7): test()
#1 {main}

ENTITY

Throwable::getTraceAsString

tostring

Error::__toString

String representation of the error

ENTITY

public

string

Error::__toString

Returns the string representation of the error.

ENTITY ENTITY

ENTITY

Returns the string representation of the error.

ENTITY

Error::__toString example

<?php
try {
    throw new Error("Some error message");
} catch(Error $e) {
    echo $e;
}
?>

    

ENTITY

Error: Some error message in /home/bjori/tmp/ex.php:3
Stack trace:
#0 {main}

ENTITY

Throwable::__toString

errorexception

ENTITY

An Error Exception.

ENTITY

ErrorException

extends

Exception

ENTITY

protected

int

severity

E_ERROR

ENTITY

ENTITY

ENTITY

ENTITY

severity
The severity of the exception

ENTITY

Use set_error_handler to change error messages into ErrorException

 
<?php

set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) {
    if (!(error_reporting() & $errno)) {
        // This error code is not included in error_reporting.
        return;
    }

    if ($errno === E_DEPRECATED || $errno === E_USER_DEPRECATED) {
        // Do not throw an Exception for deprecation warnings as new or unexpected
        // deprecations would break the application.
        return;
    }

    throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});

// Unserializing broken data triggers a warning which will be turned into an
// ErrorException by the error handler.
unserialize('broken data');

?>

     

ENTITY

Fatal error: Uncaught ErrorException: unserialize(): Error at offset 0 of 11 bytes in test.php:16
Stack trace:
#0 [internal function]: {closure}(2, 'unserialize(): ...', 'test.php', 16)
#1 test.php(16): unserialize('broken data')
#2 {main}
  thrown in test.php on line 16

ENTITY ENTITY

construct

ErrorException::__construct

Constructs the exception

ENTITY

public

ErrorException::__construct

string

message

""

int

code

0

int

severity

E_ERROR

string

null

filename

ENTITY

int

null

line

ENTITY

Throwable

null

previous

ENTITY

Constructs the Exception.

ENTITY

message
The Exception message to throw.

code
The Exception code.

severity
The severity level of the exception.

[!NOTE] While the severity can be any int value, it is intended that the error constants be used.

filename
The filename where the exception is thrown.

line
The line number where the exception is thrown.

previous
The previous exception used for the exception chaining.

ENTITY

ENTITY ENTITY
8.0.0 filename and line are nullable now. Previously, their defaults were __FILE__ and __LINE__, respectively.

getseverity

ErrorException::getSeverity

Gets the exception severity

ENTITY

final

public

int

ErrorException::getSeverity

Returns the severity of the exception.

ENTITY ENTITY

ENTITY

Returns the severity level of the exception.

ENTITY

ErrorException::getSeverity example

<?php
try {
    throw new ErrorException("Exception message", 0, E_USER_ERROR);
} catch(ErrorException $e) {
    echo "This exception severity is: " . $e->getSeverity();
    var_dump($e->getSeverity() === E_USER_ERROR);
}
?>

    

ENTITY

This exception severity is: 256
bool(true)

exception

ENTITY

Exception is the base class for exceptions that can be handled during normal operation.

ENTITY

Exception

implements

Throwable

ENTITY

protected

string

message

""

private

string

string

""

protected

int

code

protected

string

file

""

protected

int

line

private

array

trace

[]

private

Throwable

null

previous

null

ENTITY

ENTITY

message
The exception message

code
The exception code

file
The filename where the exception was created

line
The line where the exception was created

previous
The previously thrown exception

string
The string representation of the stack trace

trace
The stack trace as an array

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

clone

Exception::__clone

Clone the exception

ENTITY

private

void

Exception::__clone

Exceptions do not support cloning; this method exists only to prevent it.

[!WARNING] Exceptions cannot be cloned, whether they are instances of Exception or of a subclass. Attempting to clone an exception throws an Error, which may be caught.

ENTITY ENTITY

ENTITY

ENTITY

ENTITY

Attempting to clone an exception throws an Error with the following message: Trying to clone an uncloneable object of class ClassName.

ENTITY

ENTITY ENTITY
8.1.0 Exception::__clone is no longer declared final, because declaring a private method final emits a warning as of PHP 8.0.0. Exceptions remain uncloneable.

construct

Exception::__construct

Construct the exception

ENTITY

public

Exception::__construct

string

message

""

int

code

0

Throwable

null

previous

ENTITY

Constructs the Exception.

ENTITY

message
The Exception message to throw.

code
The Exception code.

previous
The previous exception used for the exception chaining.

[!NOTE] Calling the constructor of class Exception from a subclass ignores the default arguments, if the properties $code and $message are already set.

ENTITY

[!NOTE] The message is NOT binary safe.

getcode

Exception::getCode

Gets the Exception code

ENTITY

final

public

int

Exception::getCode

Returns the Exception code.

ENTITY ENTITY

ENTITY

Returns the exception code as int in Exception but possibly as other type in Exception descendants (for example as string in PDOException).

ENTITY

Exception::getCode example

<?php
try {
    throw new Exception("Some error message", 30);
} catch(Exception $e) {
    echo "The exception code is: " . $e->getCode();
}
?>

    

ENTITY

The exception code is: 30

ENTITY

Throwable::getCode

getfile

Exception::getFile

Gets the file in which the exception was created

ENTITY

final

public

string

Exception::getFile

Get the name of the file in which the exception was created.

ENTITY ENTITY

ENTITY

Returns the filename in which the exception was created.

ENTITY

Exception::getFile example

<?php
try {
    throw new Exception;
} catch(Exception $e) {
    echo $e->getFile();
}
?>

    

ENTITY

/home/bjori/tmp/ex.php

ENTITY

Throwable::getFile

getline

Exception::getLine

Gets the line in which the exception was created

ENTITY

final

public

int

Exception::getLine

Get line number where the exception was created.

ENTITY ENTITY

ENTITY

Returns the line number where the exception was created.

ENTITY

Exception::getLine example

<?php
try {
    throw new Exception("Some error message");
} catch(Exception $e) {
    echo "The exception was created on line: " . $e->getLine();
}
?>

    

ENTITY

The exception was created on line: 3

ENTITY

Throwable::getLine

getmessage

Exception::getMessage

Gets the Exception message

ENTITY

final

public

string

Exception::getMessage

Returns the Exception message.

ENTITY ENTITY

ENTITY

Returns the Exception message as a string.

ENTITY

Exception::getMessage example

<?php
try {
    throw new Exception("Some error message");
} catch(Exception $e) {
    echo $e->getMessage();
}
?>

    

ENTITY

Some error message

ENTITY

Throwable::getMessage

getprevious

Exception::getPrevious

Returns previous Throwable

ENTITY

final

public

Throwable

null

Exception::getPrevious

Returns previous Throwable (which had been passed as the third parameter of Exception::__construct).

ENTITY ENTITY

ENTITY

Returns the previous Throwable if available or ENTITY otherwise.

ENTITY

Exception::getPrevious example

Looping over, and printing out, exception trace.

<?php
class MyCustomException extends Exception {}

function doStuff() {
    try {
        throw new InvalidArgumentException("You are doing it wrong!", 112);
    } catch(Exception $e) {
        throw new MyCustomException("Something happened", 911, $e);
    }
}


try {
    doStuff();
} catch(Exception $e) {
    do {
        printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e));
    } while($e = $e->getPrevious());
}
?>

    

ENTITY

/home/bjori/ex.php:8 Something happened (911) [MyCustomException]
/home/bjori/ex.php:6 You are doing it wrong! (112) [InvalidArgumentException]

ENTITY

Throwable::getPrevious

gettrace

Exception::getTrace

Gets the stack trace

ENTITY

final

public

array

Exception::getTrace

Returns the Exception stack trace.

ENTITY ENTITY

ENTITY

Returns the Exception stack trace as an array.

ENTITY

Exception::getTrace example

<?php
function test() {
 throw new Exception;
}

try {
 test();
} catch(Exception $e) {
 var_dump($e->getTrace());
}
?>

    

ENTITY

array(1) {
  [0]=>
  array(4) {
    ["file"]=>
    string(22) "/home/bjori/tmp/ex.php"
    ["line"]=>
    int(7)
    ["function"]=>
    string(4) "test"
    ["args"]=>
    array(0) {
    }
  }
}

ENTITY

Throwable::getTrace

gettraceasstring

Exception::getTraceAsString

Gets the stack trace as a string

ENTITY

final

public

string

Exception::getTraceAsString

Returns the Exception stack trace as a string.

ENTITY ENTITY

ENTITY

Returns the Exception stack trace as a string.

ENTITY

Exception::getTraceAsString example

<?php
function test() {
    throw new Exception;
}

try {
    test();
} catch(Exception $e) {
    echo $e->getTraceAsString();
}
?>

    

ENTITY

#0 /home/bjori/tmp/ex.php(7): test()
#1 {main}

ENTITY

Throwable::getTraceAsString

tostring

Exception::__toString

String representation of the exception

ENTITY

public

string

Exception::__toString

Returns the string representation of the exception.

ENTITY ENTITY

ENTITY

Returns the string representation of the exception.

ENTITY

Exception::__toString example

<?php
try {
    throw new Exception("Some error message");
} catch(Exception $e) {
    echo $e;
}
?>

    

ENTITY

exception 'Exception' with message 'Some error message' in /home/bjori/tmp/ex.php:3
Stack trace:
#0 {main}

ENTITY

Throwable::__toString

Predefined Exceptions

See also the SPL Exceptions.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

fiber

ENTITY

Fibers represent full-stack, interruptible functions. Fibers may be suspended from anywhere in the call-stack, pausing execution within the fiber until the fiber is resumed at a later time.

ENTITY

final

Fiber

ENTITY

ENTITY

Fibers overview

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

construct

Fiber::__construct

Creates a new Fiber instance

ENTITY

public

Fiber::__construct

callable

callback

ENTITY

callback
The callable to invoke when starting the fiber. Arguments given to Fiber::start will be provided as arguments to the given callable.

getcurrent

Fiber::getCurrent

Gets the currently executing Fiber instance

ENTITY

public

static

Fiber

null

Fiber::getCurrent

ENTITY ENTITY

ENTITY

Returns the currently executing Fiber instance or ENTITY if this method is called from outside a fiber.

getreturn

Fiber::getReturn

Gets the value returned by the Fiber

ENTITY

public

mixed

Fiber::getReturn

ENTITY ENTITY

ENTITY

Returns the value returned by the callable provided to Fiber::__construct. If the fiber has not returned a value, either because it has not been started, has not terminated, or threw an exception, a FiberError will be thrown.

isrunning

Fiber::isRunning

Determines if the fiber is running

ENTITY

public

bool

Fiber::isRunning

ENTITY ENTITY

ENTITY

Returns ENTITY only if the fiber is running. A fiber is considered running after a call to Fiber::start, Fiber::resume, or Fiber::throw that has not yet returned. Returns ENTITY if the fiber is not running.

isstarted

Fiber::isStarted

Determines if the fiber has started

ENTITY

public

bool

Fiber::isStarted

ENTITY ENTITY

ENTITY

Returns ENTITY only after the fiber has been started; otherwise ENTITY is returned.

issuspended

Fiber::isSuspended

Determines if the fiber is suspended

ENTITY

public

bool

Fiber::isSuspended

ENTITY ENTITY

ENTITY

Returns ENTITY if the fiber is currently suspended; otherwise ENTITY is returned.

isterminated

Fiber::isTerminated

Determines if the fiber has terminated

ENTITY

public

bool

Fiber::isTerminated

ENTITY ENTITY

ENTITY

Returns ENTITY only after the fiber has terminated, either by returning or throwing an exception; otherwise ENTITY is returned.

resume

Fiber::resume

Resumes execution of the fiber with a value

ENTITY

public

mixed

Fiber::resume

mixed

value

ENTITY

Resumes the fiber using the given value as the result of the current Fiber::suspend call.

If the fiber is not suspended when this method is called, a FiberError will be thrown.

ENTITY

value
The value to resume the fiber. This value will be the return value of the current Fiber::suspend call.

ENTITY

The value provided to the next call to Fiber::suspend or ENTITY if the fiber returns. If the fiber throws an exception before suspending, it will be thrown from the call to this method.

start

Fiber::start

Start execution of the fiber

ENTITY

public

mixed

Fiber::start

mixed

args

A variadic list of arguments to provide to the callable used when constructing the fiber.

If the fiber has already been started when this method is called, a FiberError will be thrown.

ENTITY

args
The arguments to use when invoking the callable given to the fiber constructor.

ENTITY

The value provided to the first call to Fiber::suspend or ENTITY if the fiber returns. If the fiber throws an exception before suspending, it will be thrown from the call to this method.

suspend

Fiber::suspend

Suspends execution of the current fiber

ENTITY

public

static

mixed

Fiber::suspend

mixed

value

ENTITY

Suspends execution of the current fiber. The value provided to this method will be returned from the call to Fiber::start, Fiber::resume, or Fiber::throw that switched execution into the current fiber.

When the fiber is resumed, this method returns the value provided to Fiber::resume. If the fiber is resumed using Fiber::throw, the exception given to that method will be thrown from the call to this method.

If this method is called from outside a fiber, a FiberError will be thrown.

ENTITY

value
The value to return from the call to Fiber::start, Fiber::resume, or Fiber::throw that switched execution into the current fiber.

ENTITY

The value provided to Fiber::resume.

throw

Fiber::throw

Resumes execution of the fiber with an exception

ENTITY

public

mixed

Fiber::throw

Throwable

exception

Resumes the fiber by throwing the given exception from the current Fiber::suspend call.

If the fiber is not suspended when this method is called, a FiberError will be thrown.

ENTITY

exception
The exception to throw into the fiber from the current Fiber::suspend call.

ENTITY

The value provided to the next call to Fiber::suspend or ENTITY if the fiber returns. If the fiber throws an exception before suspending, it will be thrown from the call to this method.

ENTITY

<?php

$fiber = new Fiber(function () {
   try {
       // Suspend execution of the fiber declaring an interruption point
       Fiber::suspend();
   } catch (Throwable $e) {
       echo $e->getMessage();
   }
});

$fiber->start();

// Resumes execution of the fiber with
// passing the Exception to throw at the interruption point
$fiber->throw(new Exception('Message of an exception thrown at the current interrupt point'));

?>

   

ENTITY

Message of an exception thrown at the current interrupt point

fibererror

ENTITY

FiberError is thrown when an invalid operation is performed on a Fiber.

ENTITY

final

FiberError

extends

Error

ENTITY

ENTITY

ENTITY

ENTITY

construct

FiberError::__construct

Constructor to disallow direct instantiation

ENTITY

public

FiberError::__construct

ENTITY ENTITY

ENTITY

Throws an Error exception when called.

generator

ENTITY

Generator objects are returned from generators.

[!CAUTION] Generator objects cannot be instantiated via new.

ENTITY

final

Generator

implements

Iterator

ENTITY

ENTITY

See also object iteration.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

current

Generator::current

Get the yielded value

ENTITY

public

mixed

Generator::current

ENTITY ENTITY

ENTITY

Returns the yielded value.

getreturn

Generator::getReturn

Get the return value of a generator

ENTITY

public

mixed

Generator::getReturn

ENTITY ENTITY

ENTITY

Returns the generator's return value once it has finished executing.

ENTITY

Generator::getReturn example

<?php

$gen = (function() {
    yield 1;
    yield 2;

    return 3;
})();

foreach ($gen as $val) {
    echo $val, PHP_EOL;
}

echo $gen->getReturn(), PHP_EOL;

    

ENTITY

1
2
3

key

Generator::key

Get the yielded key

ENTITY

public

mixed

Generator::key

Gets the key of the yielded value.

ENTITY ENTITY

ENTITY

Returns the yielded key.

ENTITY

Generator::key example

<?php

function Gen()
{
    yield 'key' => 'value';
}

$gen = Gen();

echo "{$gen->key()} => {$gen->current()}";

    

ENTITY

key => value

next

Generator::next

Resume execution of the generator

ENTITY

public

void

Generator::next

Calling Generator::next has the same effect as calling Generator::send with ENTITY as argument.

ENTITY ENTITY

ENTITY

ENTITY

rewind

Generator::rewind

Execute the generator up to and including the first yield

ENTITY

public

void

Generator::rewind

Executes the generator up to and including the first ENTITY. If the generator is already at the first ENTITY, no action will be taken. If the generator has ever advanced beyond a ENTITY expression, this method will throw an Exception.

[!NOTE] This is the first method called when starting a ENTITY loop. It will not be executed after ENTITY loops.

ENTITY ENTITY

ENTITY

ENTITY

ENTITY

Generator::rewind example

<?php

function generator(): Generator
{
    echo "I'm a generator!\n";

    for ($i = 1; $i <= 3; $i++) {
        yield $i;
    }
}

// Initialize the generator
$generator = generator();

// Rewind the generator to the beginning of the first yield expression,
// if it's not already there
$generator->rewind(); // I'm a generator!

// Nothing happens here; the generator is already rewound
$generator->rewind(); // No output (NULL)

// This rewinds the generator to the first yield expression,
// if it's not already there, and iterates over the generator
foreach ($generator as $value) {
    // After yielding the first value, the generator remains at
    // the first yield expression until it resumes execution and advances to the next yield
    echo $value, PHP_EOL; // 1

    break;
}

// Resume and rewind again. No error occurs because the generator has not advanced beyond the first yield
$generator->rewind();

echo $generator->current(), PHP_EOL; // 1

// No error occurs, the generator is still at the first yield
$generator->rewind();

// This advances the generator to the second yield expression
$generator->next();

try {
    // This will throw an Exception,
    // because the generator has already advanced to the second yield
    $generator->rewind(); // Fatal error: Uncaught Exception: Cannot rewind a generator that was already run
} catch (Exception $e) {
    echo $e->getMessage();
}

?>

    

ENTITY

I'm a generator!
1
1
Cannot rewind a generator that was already run

send

Generator::send

Send a value to the generator

ENTITY

public

mixed

Generator::send

mixed

value

Sends the given value to the generator as the result of the current ENTITY expression and resumes execution of the generator.

If the generator is not at a ENTITY expression when this method is called, it will first be let to advance to the first ENTITY expression before sending the value. As such it is not necessary to "prime" PHP generators with a Generator::next call (like it is done in Python).

ENTITY

value
Value to send into the generator. This value will be the return value of the ENTITY expression the generator is currently at.

ENTITY

Returns the yielded value.

ENTITY

Using Generator::send to inject values

<?php
function printer() {
    echo "I'm printer!".PHP_EOL;
    while (true) {
        $string = yield;
        echo $string.PHP_EOL;
    }
}

$printer = printer();
$printer->send('Hello world!');
$printer->send('Bye world!');
?>

    

ENTITY

I'm printer!
Hello world!
Bye world!

throw

Generator::throw

Throw an exception into the generator

ENTITY

public

mixed

Generator::throw

Throwable

exception

Throws an exception into the generator and resumes execution of the generator. The behavior will be the same as if the current ENTITY expression was replaced with a throw $exception statement.

If the generator is already closed when this method is invoked, the exception will be thrown in the caller's context instead.

ENTITY

exception
Exception to throw into the generator.

ENTITY

Returns the yielded value.

ENTITY

Throwing an exception into a generator

<?php
function gen() {
    echo "Foo\n";
    try {
        yield;
    } catch (Exception $e) {
        echo "Exception: {$e->getMessage()}\n";
    }
    echo "Bar\n";
}
 
$gen = gen();
$gen->rewind();
$gen->throw(new Exception('Test'));
?>

    

ENTITY

Foo
Exception: Test
Bar

valid

Generator::valid

Check if the iterator has been closed

ENTITY

public

bool

Generator::valid

ENTITY ENTITY

ENTITY

Returns ENTITY if the iterator has been closed. Otherwise returns ENTITY.

wakeup

Generator::__wakeup

Serialize callback

ENTITY

public

void

Generator::__wakeup

Throws an exception as generators can't be serialized.

ENTITY ENTITY

ENTITY

ENTITY

Predefined Interfaces and Classes

See also the SPL Interfaces and reserved classes.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

internaliterator

ENTITY

Class to ease implementing IteratorAggregate for internal classes.

ENTITY

final

InternalIterator

implements

Iterator

ENTITY

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

construct

InternalIterator::__construct

Private constructor to disallow direct instantiation

ENTITY

private

InternalIterator::__construct

ENTITY ENTITY

current

InternalIterator::current

Return the current element

ENTITY

public

mixed

InternalIterator::current

Returns the current element.

ENTITY ENTITY

ENTITY

Returns the current element.

key

InternalIterator::key

Return the key of the current element

ENTITY

public

mixed

InternalIterator::key

Returns the key of the current element.

ENTITY ENTITY

ENTITY

Returns the key of the current element.

next

InternalIterator::next

Move forward to next element

ENTITY

public

void

InternalIterator::next

Moves the current position to the next element.

ENTITY ENTITY

ENTITY

ENTITY

rewind

InternalIterator::rewind

Rewind the Iterator to the first element

ENTITY

public

void

InternalIterator::rewind

Rewinds back to the first element of the Iterator.

ENTITY ENTITY

ENTITY

ENTITY

valid

InternalIterator::valid

Check if current position is valid

ENTITY

public

bool

InternalIterator::valid

Checks if current position is valid.

ENTITY ENTITY

ENTITY

Returns whether the current position is valid.

iterator

ENTITY

Interface for external iterators or objects that can be iterated themselves internally.

ENTITY

Iterator

extends

Traversable

ENTITY

Predefined iterators

PHP already provides a number of iterators for many day-to-day tasks. See SPL iterators for a list.

ENTITY

Basic usage

This example demonstrates in which order methods are called when using ENTITY with an iterator.

<?php
class myIterator implements Iterator {
    private $position = 0;
    private $array = array(
        "firstelement",
        "secondelement",
        "lastelement",
    );  

    public function __construct() {
        $this->position = 0;
    }

    public function rewind(): void {
        var_dump(__METHOD__);
        $this->position = 0;
    }

    #[\ReturnTypeWillChange]
    public function current() {
        var_dump(__METHOD__);
        return $this->array[$this->position];
    }

    #[\ReturnTypeWillChange]
    public function key() {
        var_dump(__METHOD__);
        return $this->position;
    }

    public function next(): void {
        var_dump(__METHOD__);
        ++$this->position;
    }

    public function valid(): bool {
        var_dump(__METHOD__);
        return isset($this->array[$this->position]);
    }
}

$it = new myIterator;

foreach($it as $key => $value) {
    var_dump($key, $value);
    echo "\n";
}
?>

    

ENTITY

string(18) "myIterator::rewind"
string(17) "myIterator::valid"
string(19) "myIterator::current"
string(15) "myIterator::key"
int(0)
string(12) "firstelement"

string(16) "myIterator::next"
string(17) "myIterator::valid"
string(19) "myIterator::current"
string(15) "myIterator::key"
int(1)
string(13) "secondelement"

string(16) "myIterator::next"
string(17) "myIterator::valid"
string(19) "myIterator::current"
string(15) "myIterator::key"
int(2)
string(11) "lastelement"

string(16) "myIterator::next"
string(17) "myIterator::valid"

ENTITY

See also object iteration.

ENTITY ENTITY ENTITY ENTITY ENTITY

current

Iterator::current

Return the current element

ENTITY

public

mixed

Iterator::current

Returns the current element.

ENTITY ENTITY

ENTITY

Can return any type.

key

Iterator::key

Return the key of the current element

ENTITY

public

mixed

Iterator::key

Returns the key of the current element.

ENTITY ENTITY

ENTITY

Returns scalar on success, or ENTITY on failure.

ENTITY

Issues E_NOTICE on failure.

next

Iterator::next

Move forward to next element

ENTITY

public

void

Iterator::next

Moves the current position to the next element.

[!NOTE] This method is called after each ENTITY loop.

ENTITY ENTITY

ENTITY

Any returned value is ignored.

rewind

Iterator::rewind

Rewind the Iterator to the first element

ENTITY

public

void

Iterator::rewind

Rewinds back to the first element of the Iterator.

[!NOTE] This is the first method called when starting a ENTITY loop. It will not be executed after ENTITY loops.

As ENTITY always calls this method before starting iteration, manually advancing the iterator position (for example via SplFileObject::seek) will be reset.

To iterate without rewinding the iterator, wrap it in a NoRewindIterator.

ENTITY ENTITY

ENTITY

Any returned value is ignored.

valid

Iterator::valid

Checks if current position is valid

ENTITY

public

bool

Iterator::valid

This method is called after Iterator::rewind and Iterator::next to check if the current position is valid.

ENTITY ENTITY

ENTITY

The return value will be casted to bool and then evaluated. ENTITY

iteratoraggregate

ENTITY

Interface to create an external Iterator.

ENTITY

IteratorAggregate

extends

Traversable

ENTITY

ENTITY

Basic usage

<?php

class myData implements IteratorAggregate
{
    public function getIterator(): Traversable
    {
        return new ArrayIterator([
            "key one" => "item one",
            "key two" => "item two",
            "key three" => "item three"
        ]);
    }
}

$obj = new myData();

foreach ($obj as $key => $value) {
    var_dump($key, $value);
    echo "\n";
}

    

ENTITY

string(7) "key one"
string(8) "item one"

string(7) "key two"
string(8) "item two"

string(9) "key three"
string(10) "item three"

ENTITY

getiterator

IteratorAggregate::getIterator

Retrieve an external iterator or traversable

ENTITY

public

Traversable

IteratorAggregate::getIterator

Returns an external iterator or traversable.

ENTITY ENTITY

ENTITY

An instance of an object implementing Iterator or Traversable

ENTITY

Throws an Exception on failure.

parseerror

ENTITY

ParseError is thrown when an error occurs while parsing PHP code, such as when eval is called.

[!NOTE] ParseError extends CompileError as of PHP 7.3.0. Formerly, it extended Error.

ENTITY

ParseError

extends

CompileError

ENTITY

ENTITY

php-incomplete-class

ENTITY

Created by unserialize when trying to unserialize an undefined class or a class that is not listed in the allowed_classes of unserialize's options array.

Prior to PHP 7.2.0, using is_object on the __PHP_Incomplete_Class class would return ENTITY. As of PHP 7.2.0, ENTITY will be returned.

ENTITY

#[\AllowDynamicProperties]

final

__PHP_Incomplete_Class

This class has no default properties or methods. When created by unserialize, in addition to all unserialized properties and values the object will have a __PHP_Incomplete_Class_Name property which will contain the name of the unserialized class.

ENTITY

ENTITY ENTITY
8.0.0 This class is now final.

ENTITY

Created by unserialize

<?php

class MyClass
{
    public string $property = "myValue";
}

$myObject = new MyClass;

$foo = serialize($myObject);

// unserializes all objects into __PHP_Incomplete_Class objects
$disallowed = unserialize($foo, ["allowed_classes" => false]);

var_dump($disallowed);

// unserializes all objects into __PHP_Incomplete_Class objects except those of MyClass2 and MyClass3
$disallowed2 = unserialize($foo, ["allowed_classes" => ["MyClass2", "MyClass3"]]);

var_dump($disallowed2);

// unserializes undefined class into __PHP_Incomplete_Class object
$undefinedClass = unserialize('O:16:"MyUndefinedClass":0:{}');

var_dump($undefinedClass);

    

ENTITY

object(__PHP_Incomplete_Class)#2 (2) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(7) "MyClass"
  ["property"]=>
  string(7) "myValue"
}
object(__PHP_Incomplete_Class)#3 (2) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(7) "MyClass"
  ["property"]=>
  string(7) "myValue"
}
object(__PHP_Incomplete_Class)#4 (1) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(16) "MyUndefinedClass"
}

requestparsebodyexception

ENTITY

A RequestParseBodyException is thrown in request_parse_body when the request body is invalid, according to the Content-Type header.

ENTITY

RequestParseBodyException

extends

Exception

ENTITY

ENTITY

construct

ReturnTypeWillChange::__construct

Construct a new ReturnTypeWillChange attribute instance

ENTITY

public

ReturnTypeWillChange::__construct

Constructs a new ReturnTypeWillChange instance.

ENTITY ENTITY

construct

SensitiveParameter::__construct

Construct a new SensitiveParameter attribute instance

ENTITY

public

SensitiveParameter::__construct

Constructs a new SensitiveParameter instance.

ENTITY ENTITY

sensitiveparametervalue

ENTITY

The SensitiveParameterValue class allows wrapping sensitive values to protect them against accidental exposure.

Values of parameters having the SensitiveParameter attribute will automatically be wrapped inside of a SensitiveParameterValue object within stack traces.

ENTITY

final

SensitiveParameterValue

ENTITY

private

readonly

mixed

value

ENTITY

ENTITY

value
The sensitive value to be protected against accidental exposure.

ENTITY ENTITY ENTITY

construct

SensitiveParameterValue::__construct

Constructs a new SensitiveParameterValue object

ENTITY

public

SensitiveParameterValue::__construct

mixed

value

Construct a SensitiveParameterValue holding a sensitive value.

ENTITY

value
An arbitrary value that should be stored inside the SensitiveParameterValue object.

debuginfo

SensitiveParameterValue::__debugInfo

Protects the sensitive value against accidental exposure

ENTITY

public

array

SensitiveParameterValue::__debugInfo

Returns an empty ENTITY to protect the sensitive value against accidental exposure when using var_dump.

ENTITY ENTITY

ENTITY

An empty ENTITY.

ENTITY

Passing a SensitiveParameterValue object to var_dump

<?php
$s = new \SensitiveParameterValue('secret');

var_dump($s);
?>

    

ENTITY

object(SensitiveParameterValue)#1 (0) {
}

getvalue

SensitiveParameterValue::getValue

Returns the sensitive value

ENTITY

public

mixed

SensitiveParameterValue::getValue

Get the sensitive value.

ENTITY ENTITY

ENTITY

The sensitive value.

ENTITY

SensitiveParameterValue::getValue example

<?php
$s = new \SensitiveParameterValue('secret');

echo "The protected value is: ", $s->getValue(), "\n";
?>

    

ENTITY

The protected value is: secret

serializable

ENTITY

Interface for customized serializing.

Classes that implement this interface no longer support __sleep() and __wakeup(). The serialize method is called whenever an instance needs to be serialized. This does not invoke __destruct or have any other side effect unless programmed inside the method. When the data is unserialized the class is known and the appropriate unserialize method is called as a constructor instead of calling __construct. The constructor can be called from within the unserialize method if desired.

[!WARNING] As of PHP 8.1.0, a class which implements Serializable without also implementing __serialize() and __unserialize() will generate a deprecation warning.

New code should use the __serialize() and __unserialize() magic methods instead, available as of PHP 7.4.0. When a class declares both them and this interface, serialize always uses __serialize() and never reaches Serializable::serialize. Unserializing is decided by the format of the data instead: a payload written by PHP 7.4.0 or later is read by __unserialize(), one written before it is still read by Serializable::unserialize. Implementing Serializable therefore remains of use for reading such older payloads, and for satisfying a Serializable type declaration; declaring all four methods covers every case, and avoids the deprecation notice.

[!NOTE] The magic methods have no interface of their own, so a class which declares them without implementing Serializable is not an instance of it. method_exists is the way to detect them.

ENTITY

Serializable

ENTITY

ENTITY

Supporting PHP 7.1.0 through 7.3.0

The magic methods carry the serialized form, and the interface methods delegate to them, so that a single representation serves both.

<?php
class Task implements Serializable
{
    private $label;

    public function __construct($label)
    {
        $this->label = $label;
    }

    public function __serialize(): array
    {
        return ['label' => $this->label];
    }

    public function __unserialize(array $data): void
    {
        $this->label = $data['label'];
    }

    // Never called as of PHP 7.4.0
    public function serialize()
    {
        return serialize($this->__serialize());
    }

    // Still called as of PHP 7.4.0, for data written before it
    public function unserialize($data)
    {
        $this->__unserialize(unserialize($data));
    }
}

var_dump(serialize(new Task('deploy')));
?>

    

ENTITY

string(40) "O:4:"Task":1:{s:5:"label";s:6:"deploy";}"

Prior to PHP 7.4.0, the same code serializes through the interface instead, and outputs string(47) "C:4:"Task":31:{a:1:{s:5:"label";s:6:"deploy";}}".

ENTITY ENTITY

serialize

Serializable::serialize

String representation of object

ENTITY

public

string

null

Serializable::serialize

Should return the string representation of the object.

ENTITY ENTITY

ENTITY

Returns the string representation of the object or ENTITY

ENTITY

Throws Exception when returning other types than strings and ENTITY.

ENTITY

__sleep(), __serialize()

unserialize

Serializable::unserialize

Constructs the object

ENTITY

public

void

Serializable::unserialize

string

data

Called during unserialization of the object.

[!NOTE] This method acts as the constructor of the object. The __construct() method will not be called after this method.

ENTITY

data
The string representation of the object.

ENTITY

The return value from this method is ignored.

ENTITY

__wakeup(), __unserialize()

stdclass

ENTITY

A generic empty class with dynamic properties.

Objects of this class can be instantiated with the new operator or created by typecasting to object. Several PHP functions also create instances of this class, e.g. json_decode, mysqli_fetch_object or PDOStatement::fetchObject.

Despite not implementing __get()/__set() magic methods, this class allows dynamic properties and does not require the #[\AllowDynamicProperties] attribute.

This is not a base class as PHP does not have a concept of a universal base class. However, it is possible to create a custom class that extends stdClass and as a result inherits the functionality of dynamic properties.

ENTITY

#[\AllowDynamicProperties]

stdClass

This class has no methods or default properties.

ENTITY

Created as a result of typecasting to object

<?php
$obj = (object) array('foo' => 'bar');
var_dump($obj);

    

ENTITY

object(stdClass)#1 (1) {
  ["foo"]=>
  string(3) "bar"
}

Created as a result of json_decode

<?php
$json = '{"foo":"bar"}';
var_dump(json_decode($json));

    

ENTITY

object(stdClass)#1 (1) {
  ["foo"]=>
  string(3) "bar"
}

Declaring dynamic properties

<?php
$obj = new stdClass();
$obj->foo = 42;
$obj->{1} = 42;
var_dump($obj);

    

ENTITY

object(stdClass)#1 (2) {
  ["foo"]=>
  int(42)
  ["1"]=>
  int(42)
}

stringable

ENTITY

The Stringable interface denotes a class as having a __toString() method. Unlike most interfaces, Stringable is implicitly present on any class that has the magic __toString() method defined, although it can and should be declared explicitly.

Its primary value is to allow functions to type check against the union type string|Stringable to accept either a string primitive or an object that can be cast to a string.

ENTITY

Stringable

ENTITY

Stringable Examples

Basic Stringable Usage

This uses constructor property promotion.

<?php
class IPv4Address implements Stringable {
    public function __construct(
        private string $oct1,
        private string $oct2,
        private string $oct3,
        private string $oct4,
    ) {}

    public function __toString(): string {
        return "$this->oct1.$this->oct2.$this->oct3.$this->oct4";
    }
}

function showStuff(string|Stringable $value) {
    // For a Stringable, this will implicitly call __toString().
    print $value;
}

$ip = new IPv4Address('123', '234', '42', '9');

showStuff($ip);
?>

     

ENTITY

123.234.42.9

ENTITY

tostring

Stringable::__toString

Gets a string representation of the object

ENTITY

public

string

Stringable::__toString

ENTITY ENTITY

ENTITY

Returns the ENTITY representation of the object.

ENTITY

__toString()

throwable

ENTITY

Throwable is the base interface for any object that can be thrown via a ENTITY statement, including Error and Exception.

[!NOTE] PHP classes cannot implement the Throwable interface directly, and must instead extend Exception.

ENTITY

Throwable

extends

Stringable

ENTITY

ENTITY

ENTITY

ENTITY ENTITY
8.0.0 Throwable implements Stringable now.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

getcode

Throwable::getCode

Gets the exception code

ENTITY

public

int

Throwable::getCode

Returns the error code associated with the thrown object.

ENTITY ENTITY

ENTITY

Returns the exception code as int in Exception but possibly as other type in Exception descendants (for example as string in PDOException).

ENTITY

Exception::getCode

getfile

Throwable::getFile

Gets the file in which the object was created

ENTITY

public

string

Throwable::getFile

Get the name of the file in which the thrown object was created.

ENTITY ENTITY

ENTITY

Returns the filename in which the thrown object was created.

ENTITY

Exception::getFile

getline

Throwable::getLine

Gets the line on which the object was instantiated

ENTITY

public

int

Throwable::getLine

Returns the line number where the thrown object was instantiated.

ENTITY ENTITY

ENTITY

Returns the line number where the thrown object was instantiated.

ENTITY

Exception::getLine

getmessage

Throwable::getMessage

Gets the message

ENTITY

public

string

Throwable::getMessage

Returns the message associated with the thrown object.

ENTITY ENTITY

ENTITY

Returns the message associated with the thrown object.

ENTITY

Exception::getMessage

getprevious

Throwable::getPrevious

Returns the previous Throwable

ENTITY

public

Throwable

null

Throwable::getPrevious

Returns any previous Throwable (for example, one provided as the third parameter to Exception::__construct).

ENTITY ENTITY

ENTITY

Returns the previous Throwable if available, or ENTITY otherwise.

ENTITY

Exception::getPrevious

gettrace

Throwable::getTrace

Gets the stack trace

ENTITY

public

array

Throwable::getTrace

Returns the stack trace as an array.

ENTITY ENTITY

ENTITY

Returns the stack trace as an array in the same format as debug_backtrace.

ENTITY

Exception::getTrace

gettraceasstring

Throwable::getTraceAsString

Gets the stack trace as a string

ENTITY

public

string

Throwable::getTraceAsString

ENTITY ENTITY

ENTITY

Returns the stack trace as a string.

ENTITY

Exception::getTraceAsString

tostring

Throwable::__toString

Gets a string representation of the thrown object

ENTITY

public

string

Throwable::__toString

ENTITY ENTITY

ENTITY

Returns the string representation of the thrown object.

ENTITY

Exception::__toString

traversable

ENTITY

Interface to detect if a class is traversable using ENTITY.

Abstract base interface that cannot be implemented alone. Instead, it must be implemented by either IteratorAggregate or Iterator.

ENTITY

Traversable

This interface has no methods; its only purpose is to be the base interface for all traversable classes.

ENTITY

ENTITY ENTITY
8.0.0 The Traversable interface can now be implemented by abstract classes. Extending classes must implement Iterator or IteratorAggregate.

ENTITY

[!NOTE] Internal (built-in) classes that implement this interface can be used in a ENTITY construct and do not need to implement IteratorAggregate or Iterator.

[!NOTE] Prior to PHP 8.0.0, this internal engine interface couldn't be directly implemented in PHP scripts — not even by abstract classes. Either IteratorAggregate or Iterator must be used instead.

typeerror

ENTITY

A TypeError may be thrown when: The value being set for a class property does not match the property's corresponding declared type., The argument type being passed to a function does not match its corresponding declared parameter type., A value being returned from a function does not match the declared function return type.

ENTITY

TypeError

extends

Error

ENTITY

ENTITY

ENTITY

ENTITY ENTITY
7.1.0 In strict mode, passing an incorrect number of arguments to a built-in PHP function no longer results in a generic TypeError. Instead, a more specific ArgumentCountError, which extends TypeError, is thrown.

unhandledmatcherror

ENTITY

An UnhandledMatchError is thrown when the subject passed to a ENTITY expression is not handled by any arm of the ENTITY expression.

ENTITY

UnhandledMatchError

extends

Error

ENTITY

ENTITY

unitenum

ENTITY

The UnitEnum interface is automatically applied to all enumerations by the engine. It may not be implemented by user-defined classes. Enumerations may not override its methods, as default implementations are provided by the engine. It is available only for type checks.

ENTITY

UnitEnum

ENTITY

ENTITY

cases

UnitEnum::cases

Generates a list of cases on an enum

ENTITY

public

static

array

UnitEnum::cases

This method will return a packed array of all cases in an enumeration, in order of declaration.

ENTITY ENTITY

ENTITY

An array of all defined cases of this enumeration, in order of declaration.

ENTITY

Basic usage

The following example illustrates how enum cases are returned.

<?php
enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

var_dump(Suit::cases());

   

ENTITY

array(4) {
  [0]=>
  enum(Suit::Hearts)
  [1]=>
  enum(Suit::Diamonds)
  [2]=>
  enum(Suit::Clubs)
  [3]=>
  enum(Suit::Spades)
}

valueerror

ENTITY

A ValueError is thrown when the type of an argument is correct but its value is incorrect. For example, passing a negative integer when the function expects a positive one, or passing an empty string/array when the function expects it to not be empty.

ENTITY

ValueError

extends

Error

ENTITY

ENTITY

variables

PHP provides predefined variables that represent external variables, built-in environment variables, and other information about the execution environment, such as the number and values of the arguments passed to the script in the CLI environment.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

argc

$argc

The number of arguments passed to script

ENTITY

Contains the number of arguments passed to the current script when running from the command line.

[!NOTE] The script's filename is always passed as an argument to the script, therefore the minimum value of $argc is 1.

[!NOTE] This variable is not available when register_argc_argv is disabled.

ENTITY

$argc example

<?php
var_dump($argc);
?>

    

When executing the example with: php script.php arg1 arg2 arg3

ENTITY

int(4)

ENTITY

[!NOTE] This is also available as $_SERVER['argc'].

ENTITY

getopt, $argv

argv

$argv

Array of arguments passed to script

ENTITY

Contains an array of all the arguments passed to the script when running from the command line.

[!NOTE] The first argument $argv[0] is always the name that was used to run the script.

[!NOTE] This variable is not available when register_argc_argv is disabled.

[!WARNING] To test if a script is being run from the command line, php_sapi_name should be used instead of checking whether $argv or $_SERVER['argv'] is set.

ENTITY

$argv example

<?php
var_dump($argv);
?>

    

When executing the example with: php script.php arg1 arg2 arg3

ENTITY

array(4) {
  [0]=>
  string(10) "script.php"
  [1]=>
  string(4) "arg1"
  [2]=>
  string(4) "arg2"
  [3]=>
  string(4) "arg3"
}

ENTITY

[!NOTE] This is also available as $_SERVER['argv'].

ENTITY

getopt, $argc

cookie

HTTP Cookies

ENTITY

An associative array of variables passed to the current script via HTTP Cookies.

ENTITY

ENTITY ENTITY

ENTITY

setcookie, Handling external variables, The filter extension

env

$_ENV

Environment variables

ENTITY

An associative array of variables passed to the current script via the environment method.

These variables are imported into PHP's global namespace from the environment under which the PHP parser is running. Many are provided by the shell under which PHP is running and different systems are likely running different kinds of shells, a definitive list is impossible. Please see your shell's documentation for a list of defined environment variables.

Other environment variables include the CGI variables, placed there regardless of whether PHP is running as a server module or CGI processor.

ENTITY

$_ENV example

<?php
echo 'My username is ' .$_ENV["USER"] . '!';
?>

    

Assuming "bjori" executes this script

ENTITY

My username is bjori!

ENTITY ENTITY

ENTITY

getenv, The filter extension

files

$_FILES

HTTP File Upload variables

ENTITY

An associative array of items uploaded to the current script via the HTTP POST method. The structure of this array is outlined in the POST method uploads section.

ENTITY ENTITY

ENTITY

move_uploaded_file, Handling File Uploads

get

$_GET

Query string variables

ENTITY

An associative array of variables passed to the current script via the URL parameters (also known as the query string). Note that this array is populated whenever a query string is present, regardless of the HTTP request method.

ENTITY

$_GET example

<?php
echo 'Hello ' . htmlspecialchars($_GET["name"]) . '!';
?>

    

Assuming the user entered http://example.com/?name=Hannes.

ENTITY

Hello Hannes!

ENTITY ENTITY

[!NOTE] The values in $_GET are automatically passed through urldecode.

ENTITY

Handling external variables, The filter extension

globals

$GLOBALS

References all variables available in global scope

ENTITY

An associative array containing references to all variables which are currently defined in the global scope of the script. The variable names are the keys of the array.

ENTITY

$GLOBALS example

<?php

function test()
{
    $foo = "local variable";

    echo '$foo in global scope: ' . $GLOBALS["foo"] . "\n";
    echo '$foo in current scope: ' . $foo . "\n";
}

$foo = "Example content";
test();

?>

    

ENTITY

$foo in global scope: Example content
$foo in current scope: local variable

[!WARNING] As of PHP 8.1.0, write access to the entire $GLOBALS array is no longer supported:

writing entire $GLOBALS will result in error.

<?php

// Generates compile-time error:
$GLOBALS = [];
$GLOBALS += [];
$GLOBALS =& $x;
$x =& $GLOBALS;
unset($GLOBALS);
array_pop($GLOBALS);
// ...and any other write/read-write operation on $GLOBALS

?>
 
     

ENTITY ENTITY

[!NOTE] Unlike all of the other superglobals, $GLOBALS has essentially always been available in PHP.

[!NOTE] As of PHP 8.1.0, $GLOBALS is now a read-only copy of the global symbol table. That is, global variables cannot be modified via its copy. Previously, $GLOBALS array is excluded from the usual by-value behavior of PHP arrays and global variables can be modified via its copy.

<?php

// Before PHP 8.1.0
$a = 1;

$globals = $GLOBALS; // Ostensibly by-value copy
$globals['a'] = 2;
var_dump($a); // int(2)

// As of PHP 8.1.0
// this no longer modifies $a. The previous behavior violated by-value semantics.
$globals = $GLOBALS;
$globals['a'] = 1;

// To restore the previous behavior, iterate its copy and assign each property back to $GLOBALS.
foreach ($globals as $key => $value) {
    $GLOBALS[$key] = $value;
}

?>

     

httpresponseheader

$http_response_header

HTTP response headers

ENTITY

Use http_get_last_response_headers instead.

ENTITY

The $http_response_header array is similar to the get_headers function. When using the HTTP wrapper, $http_response_header will be populated with the HTTP response headers. $http_response_header will be created in the local scope.

ENTITY

$http_response_header example

<?php
function get_contents() {
  file_get_contents("http://example.com");
  var_dump($http_response_header); // variable is populated in the local scope
}
get_contents();
var_dump($http_response_header); // a call to get_contents() does not populate the variable outside the function scope
?>

    

ENTITY

array(9) {
  [0]=>
  string(15) "HTTP/1.1 200 OK"
  [1]=>
  string(35) "Date: Sat, 12 Apr 2008 17:30:38 GMT"
  [2]=>
  string(29) "Server: Apache/2.2.3 (CentOS)"
  [3]=>
  string(44) "Last-Modified: Tue, 15 Nov 2005 13:24:10 GMT"
  [4]=>
  string(27) "ETag: "280100-1b6-80bfd280""
  [5]=>
  string(20) "Accept-Ranges: bytes"
  [6]=>
  string(19) "Content-Length: 438"
  [7]=>
  string(17) "Connection: close"
  [8]=>
  string(38) "Content-Type: text/html; charset=UTF-8"
}

Warning: Undefined variable $http_response_header
NULL

ENTITY

http_get_last_response_headers

http_clear_last_response_headers

phperrormsg

$php_errormsg

The previous error message

ENTITY

Use error_get_last instead.

ENTITY

$php_errormsg is a variable containing the text of the last error message generated by PHP. This variable will only be available within the scope in which the error occurred, and only if the track_errors configuration option is turned on (it defaults to off).

[!WARNING] If a user defined error handler (set_error_handler) is set $php_errormsg is only set if the error handler returns ENTITY.

ENTITY

ENTITY ENTITY
8.0.0 Directive track_errors which caused $php_errormsg to be available has been removed.
7.2.0 Directive track_errors which caused $php_errormsg to be available has been deprecated.

ENTITY

$php_errormsg example

<?php
@strpos();
echo $php_errormsg;
?>

    

ENTITY

Wrong parameter count for strpos()

ENTITY

error_get_last

post

$_POST

Form data from HTTP POST requests

ENTITY

An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.

ENTITY

$_POST example

<?php
echo 'Hello ' . htmlspecialchars($_POST["name"]) . '!';
?>

    

Assuming the user sent a POST request with name=Hannes in the body.

ENTITY

Hello Hannes!

ENTITY ENTITY

[!NOTE] To read POST data sent with other content types (e.g. application/json or application/xml) php://input must be used. Unlike $_POST, which only works with application/x-www-form-urlencoded and multipart/form-data, php://input provides direct access to the raw data from the body of the request.

ENTITY

Handling external variables, The filter extension

request

$_REQUEST

HTTP Request variables

ENTITY

An associative array that by default contains the contents of $_GET, $_POSTENTITY $_COOKIE.

ENTITY ENTITY

[!NOTE] When running on the command line , this will not include the argv and argc entries; these are present in the $_SERVER array.

[!NOTE] The variables in $_REQUEST are provided to the script via the GET, POST, and COOKIE input mechanisms and therefore could be modified by the remote user and cannot be trusted. The presence and order of variables listed in this array is defined according to the PHP request_order, and variables_order configuration directives.

ENTITY

Handling external variables

The filter extension

server

$_SERVER

Server and execution environment information

ENTITY

$_SERVER is an ENTITY containing information such as headers, paths, and script locations. The entries in this array are created by the web server, therefore there is no guarantee that every web server will provide any of these; servers may omit some, or provide others not listed here. However, most of these variables are accounted for in the CGI/1.1 specification, and are likely to be defined.

[!NOTE] When running PHP on the command line most of these entries will not be available or have any meaning.

In addition to the elements listed below, PHP will create additional elements with values from request headers. These entries will be named HTTP_ followed by the header name, capitalized and with underscores instead of hyphens. For example, the Accept-Language header would be available as $_SERVER['HTTP_ACCEPT_LANGUAGE'].

ENTITY

'PHP_SELF'
The filename of the currently executing script, relative to the document root. For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ constant contains the full path and filename of the current (i.e. included) file.

If PHP is running as a command-line processor this variable contains the script name.

'argv'
Array of arguments passed to the script. When the script is run on the command line, this gives C-style access to the command line parameters. When called via the GET method, this will contain the query string.

'argc'
Contains the number of command line parameters passed to the script (if run on the command line).

'GATEWAY_INTERFACE'
What revision of the CGI specification the server is using; e.g. 'CGI/1.1'.

'SERVER_ADDR'
The IP address of the server under which the current script is executing.

'SERVER_NAME'
The name of the server host under which the current script is executing. If the script is running on a virtual host, this will be the value defined for that virtual host.

[!NOTE] Under Apache 2, UseCanonicalName = On and ServerName must be set. Otherwise, this value reflects the hostname supplied by the client, which can be spoofed. It is not safe to rely on this value in security-dependent contexts.

'SERVER_SOFTWARE'
Server identification string, given in the headers when responding to requests.

'SERVER_PROTOCOL'
Name and revision of the information protocol via which the page was requested; e.g. 'HTTP/1.0';

'REQUEST_METHOD'
Which request method was used to access the page; e.g. 'GET', 'HEAD', 'POST', 'PUT'.

[!NOTE] PHP script is terminated after sending headers (it means after producing any output without output buffering) if the request method was HEAD.

'REQUEST_TIME'
The timestamp when PHP started processing the request.

'REQUEST_TIME_FLOAT'
The timestamp when PHP started processing the request, with microsecond precision.

'QUERY_STRING'
The query string, if any, via which the page was accessed.

'DOCUMENT_ROOT'
The document root directory under which the current script is executing, as defined in the server's configuration file.

'HTTPS'
Set to a non-empty value if the script was queried through the HTTPS protocol.

'REMOTE_ADDR'
The IP address from which the user is viewing the current page.

'REMOTE_HOST'
The Host name from which the user is viewing the current page. The reverse dns lookup is based on the REMOTE_ADDR of the user.

[!NOTE] The web server must be configured to create this variable. For example in Apache HostnameLookups On must be set inside ENTITY for it to exist. See also gethostbyaddr.

'REMOTE_PORT'
The port being used on the user's machine to communicate with the web server.

'REMOTE_USER'
The authenticated user.

'REDIRECT_REMOTE_USER'
The authenticated user if the request is internally redirected.

'SCRIPT_FILENAME'
The absolute pathname of the currently executing script.

[!NOTE] If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user.

'SERVER_ADMIN'
The value given to the SERVER_ADMIN (for Apache) directive in the web server configuration file. If the script is running on a virtual host, this will be the value defined for that virtual host.

'SERVER_PORT'
The port on the server machine being used by the web server for communication. For default setups, this will be '80'; using SSL, for instance, will change this to whatever your defined secure HTTP port is.

[!NOTE] Under Apache 2, UseCanonicalName = On, as well as UseCanonicalPhysicalPort = On must be set in order to get the physical (real) port, otherwise, this value can be spoofed, and it may or may not return the physical port value. It is not safe to rely on this value in security-dependent contexts.

'SERVER_SIGNATURE'
String containing the server version and virtual host name which are added to server-generated pages, if enabled.

'PATH_TRANSLATED'
Filesystem- (not document root-) based path to the current script, after the server has done any virtual-to-real mapping.

[!NOTE] Apache 2 users may use AcceptPathInfo = On inside httpd.conf to define PATH_INFO.

'SCRIPT_NAME'
Contains the current script's path. This is useful for pages which need to point to themselves. The __FILE__ constant contains the full path and filename of the current (i.e. included) file.

'REQUEST_URI'
The URI which was given in order to access this page; for instance, '/index.html'.

'PHP_AUTH_DIGEST'
When doing Digest HTTP authentication this variable is set to the 'Authorization' header sent by the client (which you should then use to make the appropriate validation).

'PHP_AUTH_USER'
When doing HTTP authentication this variable is set to the username provided by the user.

'PHP_AUTH_PW'
When doing HTTP authentication this variable is set to the password provided by the user.

'AUTH_TYPE'
When doing HTTP authentication this variable is set to the authentication type.

'PATH_INFO'
Contains any client-provided pathname information trailing the actual script filename but preceding the query string, if available. For instance, if the current script was accessed via the URI http://www.example.com/php/path_info.php/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain /some/stuff.

'ORIG_PATH_INFO'
Original version of 'PATH_INFO' before processed by PHP.

ENTITY

$_SERVER example

<?php
echo $_SERVER['SERVER_NAME'];
?>

    

ENTITY

www.example.com

ENTITY ENTITY

ENTITY

The filter extension

session

$_SESSION

Session variables

ENTITY

An associative array containing session variables available to the current script. See the Session functions documentation for more information on how this is used.

ENTITY ENTITY

ENTITY

session_start

superglobals

Superglobals

Built-in variables that are always available in all scopes

ENTITY

Several predefined variables in PHP are "superglobals", which means they are available in all scopes throughout a script. There is no need to do global $variable; to access them within functions or methods.

These superglobal variables are: $GLOBALS, $_SERVER, $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, $_REQUEST, $_ENV

ENTITY

[!NOTE] By default, all of the superglobals are available but there are directives that affect this availability. For further information, refer to the documentation for variables_order.

[!NOTE] Superglobals cannot be used as variable variables inside functions or class methods.

ENTITY

variable scope, The variables_order directive, The filter extension

weakmap

ENTITY

A WeakMap is a map (or dictionary) that accepts objects as keys. However, unlike the otherwise similar SplObjectStorage, an object in a key of a WeakMap does not contribute toward the object's reference count. That is, if at any point the only remaining reference to an object is the key of a WeakMap, the object will be garbage collected and removed from the WeakMap. Its primary use case is for building caches of data derived from an object that do not need to live longer than the object.

WeakMap implements ArrayAccess, Traversable (via IteratorAggregate), and Countable, so in most cases it can be used in the same fashion as an associative array.

ENTITY

final

WeakMap

implements

ArrayAccess

Countable

IteratorAggregate

ENTITY

ENTITY

WeakMap usage example

      
<?php
$wm = new WeakMap();

$o = new stdClass;

class A {
    public function __destruct() {
        echo "Dead!\n";
    }
}

$wm[$o] = new A;

var_dump(count($wm));
echo "Unsetting...\n";
unset($o);
echo "Done\n";
var_dump(count($wm));

     

ENTITY

int(1)
Unsetting...
Dead!
Done
int(0)

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

count

WeakMap::count

Counts the number of live entries in the map

ENTITY

public

int

WeakMap::count

Counts the number of live entries in the map.

ENTITY ENTITY

ENTITY

Returns the number of live entries in the map.

getiterator

WeakMap::getIterator

Retrieve an external iterator

ENTITY

public

Iterator

WeakMap::getIterator

Returns an external iterator.

ENTITY ENTITY

ENTITY

An instance of an object implementing Iterator or Traversable

ENTITY

Throws an Exception on failure.

offsetexists

WeakMap::offsetExists

Checks whether a certain object is in the map

ENTITY

public

bool

WeakMap::offsetExists

object

object

Checks whether the passed object is referenced in the map.

ENTITY

object
Object to check for.

ENTITY

Returns ENTITY if the object is contained in the map, ENTITY otherwise.

ENTITY

[!NOTE] Like isset, this method returns ENTITY if the value associated with object is ENTITY, even though the object is still contained in the map.

offsetget

WeakMap::offsetGet

Returns the value pointed to by a certain object

ENTITY

public

mixed

WeakMap::offsetGet

object

object

Returns the value pointed to by a certain object.

ENTITY

object
Some object contained as key in the map.

ENTITY

Returns the value associated to the object passed as argument.

ENTITY

Throws an Error on failure.

offsetset

WeakMap::offsetSet

Updates the map with a new key-value pair

ENTITY

public

void

WeakMap::offsetSet

object

object

mixed

value

Updates the map with a new key-value pair. If the key already existed in the map, the old value is replaced with the new.

ENTITY

object
The object serving as key of the key-value pair.

value
The arbitrary data serving as value of the key-value pair.

ENTITY

ENTITY

offsetunset

WeakMap::offsetUnset

Removes an entry from the map

ENTITY

public

void

WeakMap::offsetUnset

object

object

Removes an entry from the map.

ENTITY

object
The key object to remove from the map.

ENTITY

ENTITY

weakreference

ENTITY

Weak references allow the programmer to retain a reference to an object without preventing the object from being destroyed. They are useful for implementing cache-like structures. If the original object has been destroyed, ENTITY will be returned when calling the WeakReference::get method. The original object will be destroyed when the refcount for it drops to zero; creating weak references does not increase the refcount of the object being referenced.

WeakReferences cannot be serialized.

ENTITY

final

WeakReference

ENTITY

WeakReference Examples

Basic WeakReference Usage

<?php

$obj = new stdClass();
$weakref = WeakReference::create($obj);

var_dump($weakref->get());

unset($obj);

var_dump($weakref->get());

?>

     

ENTITY

object(stdClass)#1 (0) {
}
NULL

ENTITY

ENTITY ENTITY
8.4.0 The output of WeakReference::__debugInfo now includes the referenced object, or ENTITY if the reference is no longer valid.

ENTITY ENTITY ENTITY

construct

WeakReference::__construct

Constructor that disallows instantiation

ENTITY

public

WeakReference::__construct

This method exists only to disallow instantiation of the WeakReference class. Weak references are to be instantiated with the factory method WeakReference::create.

ENTITY ENTITY

ENTITY

WeakReference::create

create

WeakReference::create

Create a new weak reference

ENTITY

public

static

WeakReference

WeakReference::create

object

object

Creates a new WeakReference.

ENTITY

object
The object to be weakly referenced.

ENTITY

Returns a new WeakReference, or the existing instance if there was already a WeakReference to the same object.

get

WeakReference::get

Get a weakly referenced Object

ENTITY

public

object

null

WeakReference::get

Gets a weakly referenced object. If the object has already been destroyed, ENTITY is returned.

ENTITY ENTITY

ENTITY

Returns the referenced ENTITY, or ENTITY if the object has been destroyed.

References Explained

What References Are

References in PHP are a means to access the same variable content by different names. They are not like C pointers; for instance, you cannot perform pointer arithmetic using them, they are not actual memory addresses, and so on. See What References Are Not for more information. Instead, they are symbol table aliases. Note that in PHP, variable name and variable content are different, so the same content can have different names. The closest analogy is with Unix filenames and files - variable names are directory entries, while variable content is the file itself. References can be likened to hardlinking in Unix filesystem.

What References Do

There are three basic operations performed using references: assigning by reference, passing by reference, and returning by reference. This section will give an introduction to these operations, with links for further reading.

Assign By Reference

In the first of these, PHP references allow you to make two variables refer to the same content. Meaning, when you do:

<?php
$a =& $b;

      

it means that $a and $b point to the same content.

[!NOTE] $a and $b are completely equal here. $a is not pointing to $b or vice versa. $a and $b are pointing to the same place.

[!NOTE] If you assign, pass, or return an undefined variable by reference, it will get created.

Using references with undefined variables

<?php

function foo(&$var) {}

foo($a); // $a is "created" and assigned to null

$b = array();
foo($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)

$c = new stdClass();
foo($c->d);
var_dump(property_exists($c, 'd')); // bool(true)

       

The same syntax can be used with functions that return references:

<?php
$foo =& find_var($bar);

      

Using the same syntax with a function that does not return by reference will give an error, as will using it with the result of the new operator. Although objects are passed around as pointers, these are not the same as references, as explained under Objects and references.

[!WARNING] If you assign a reference to a variable declared global inside a function, the reference will be visible only inside the function. You can avoid this by using the $GLOBALS array.

Referencing global variables inside functions

<?php
$var1 = "Example variable";
$var2 = "";

function global_references($use_globals)
{
    global $var1, $var2;

    if (!$use_globals) {
        $var2 =& $var1; // visible only inside the function
    } else {
        $GLOBALS["var2"] =& $var1; // visible also in global context
    }
}

global_references(false);
echo "var2 is set to '$var2'\n"; // var2 is set to ''

global_references(true);
echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'

       

Think about global $var; as a shortcut to $var =ENTITY $GLOBALS['var'];. Thus assigning another reference to $var only changes the local variable's reference.

[!NOTE] If you assign a value to a variable with references in a ENTITY statement, the references are modified too.

References and foreach statement

<?php
$ref = 0;
$row =& $ref;

foreach (array(1, 2, 3) as $row) {
    // Do something
}

echo $ref; // 3 - last element of the iterated array

       

While not being strictly an assignment by reference, expressions created with the language construct array() can also behave as such by prefixing ENTITY to the array element to add. Example:

<?php
$a = 1;
$b = array(2, 3);

$arr = array(&$a, &$b[0], &$b[1]);
$arr[0]++;
$arr[1]++;
$arr[2]++;
/* $a == 2, $b == array(3, 4); */
var_dump($a);
var_dump($b);

      

Note, however, that references inside arrays are potentially dangerous. Doing a normal (not by reference) assignment with a reference on the right side does not turn the left side into a reference, but references inside arrays are preserved in these normal assignments. This also applies to function calls where the array is passed by value. Example:

<?php

/* Assignment of scalar variables */
$a = 1;
$b =& $a;
$c = $b;
$c = 7; // $c is not a reference; no change to $a or $b
print "a = {$a}; b = {$b}; c = {$c}\n\n";

/* Assignment of array variables */
$arr = array(1);
$a =& $arr[0]; // $a and $arr[0] are in the same reference set
$arr2 = $arr; // Not an assignment-by-reference!
$arr2[0]++;
/* $a == 2, $arr == array(2) */
/* The contents of $arr are changed even though it's not a reference! */
print "a = {$a}\n";
var_dump($arr);
var_dump($arr2);

      

In other words, the reference behavior of arrays is defined in an element-by-element basis; the reference behavior of individual elements is dissociated from the reference status of the array container.

Pass By Reference

The second thing references do is to pass variables by reference. This is done by making a local variable in a function and a variable in the calling scope referencing the same content. Example:

<?php
function foo(&$var)
{
    $var++;
}

$a = 5;
foo($a);
print $a;

      

will make $a to be 6. This happens because in the function foo the variable $var refers to the same content as $a. For more information on this, read the passing by reference section.

Return By Reference

The third thing references can do is return by reference.

What References Are Not

As said before, references are not pointers. That means, the following construct won't do what you expect:

<?php
function foo(&$var)
{
    $var =& $GLOBALS["baz"];
}

foo($bar);

     

What happens is that $var in foo will be bound with $bar in the caller, but then re-bound with $GLOBALS["baz"]. There's no way to bind $bar in the calling scope to something else using the reference mechanism, since $bar is not available in the function foo (it is represented by $var, but $var has only variable contents and not name-to-value binding in the calling symbol table). You can use returning references to reference variables selected by the function.

Passing by Reference

You can pass a variable by reference to a function so the function can modify the variable. The syntax is as follows:

<?php
function foo(&$var)
{
    $var++;
}

$a = 5;
foo($a);
print $a; // $a is 6 here

     

[!NOTE] There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference.

The following things can be passed by reference:

No other expressions should be passed by reference, as the result is undefined. For example, the following examples of passing by reference are invalid:

<?php

function foo(&$var)
{
    $var++;
}

function bar() // Note the missing &
{
    $a = 5;
    return $a;
}

foo(bar()); // Produces a notice

foo($a = 5); // Expression, not variable
foo(5); // Produces fatal error

class Foobar {}

foo(new Foobar()) // Produces a notice as of PHP 7.0.7
                  // Notice: Only variables should be passed by reference

     

Returning References

Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so. To return references, use this syntax:

<?php

class Foo
{
    public $value = 42;

    public function &getValue()
    {
        return $this->value;
    }
}

$obj = new Foo();
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42
$obj->value = 2;
echo $myValue;                // Prints the new value of $obj->value, i.e. 2

     

In this example, the property of the object returned by the getValue function would be set, not the copy, as it would be without using reference syntax.

[!NOTE] Unlike parameter passing, here you have to use ENTITY in both places - to indicate that you want to return by reference, not a copy, and to indicate that reference binding, rather than usual assignment, should be done for $myValue.

[!NOTE] If you try to return a reference from a function with the syntax: return ($this->value); this will not work as you are attempting to return the result of an expression, and not a variable, by reference. You can only return variables by reference from a function - nothing else.

To use the returned reference, you must use reference assignment:

<?php

function &collector()
{
    static $collection = array();
    return $collection;
}

$collection = &collector();
// Now the $collection is a referenced variable that references the static array inside the function

$collection[] = 'foo';

print_r(collector());

     

ENTITY

Array
(
    [0] => foo
)

[!NOTE] If the assignment is done without the ENTITY symbol, e.g. $collection = collector();, the $collection variable will receive a copy of the value, not the reference returned by the function.

To pass the returned reference to another function expecting a reference you can use this syntax:

<?php

function &collector()
{
    static $collection = array();
    return $collection;
}

array_push(collector(), 'foo');

     

[!NOTE] Note that array_push(ENTITYcollector(), 'foo'); will not work, it results in a fatal error.

Unsetting References

When you unset the reference, you just break the binding between variable name and variable content. This does not mean that variable content will be destroyed. For example:

<?php

$a = 1;
$b =& $a;
unset($a); 
var_dump($a);
var_dump($b);

     

won't unset $b, just $a.

Again, it might be useful to think about this as analogous to the Unix unlink call.

Spotting References

Many syntax constructs in PHP are implemented via referencing mechanisms, so everything mentioned herein about reference binding also applies to these constructs. Some constructs, like passing and returning by reference, are mentioned above. Other constructs that use references are:

global References

When you declare a variable as global $var you are in fact creating reference to a global variable. That means, this is the same as:

<?php
$var =& $GLOBALS["var"];

      

This also means that unsetting $var won't unset the global variable.

Types

Introduction

Every single expression in PHP has one of the following built-in types depending on its value:

PHP is a dynamically typed language, which means that by default there is no need to specify the type of a variable, as this will be determined at runtime. However, it is possible to statically type some aspect of the language via the use of type declarations. Different types that are supported by PHP's type system can be found at the type system page.

Types restrict the kind of operations that can be performed on them. However, if an expression/variable is used in an operation which its type does not support, PHP will attempt to type juggle the value into a type that supports the operation. This process depends on the context in which the value is used. For more information, see the section on Type Juggling.

[!TIP] The type comparison tables may also be useful, as various examples of comparison between values of different types are present.

[!NOTE] It is possible to force an expression to be evaluated to a certain type by using a type cast. A variable can also be type cast in-place by using the settype function on it.

To check the value and type of an expression, use the var_dump function. To retrieve the type of an expression, use the get_debug_type function. However, to check if an expression is of a certain type use the is_type functions instead.

Different Types

<?php
$a_bool = true;   // a bool
$a_str  = "foo";  // a string
$a_str2 = 'foo';  // a string
$an_int = 12;     // an int

echo get_debug_type($a_bool), "\n";
echo get_debug_type($a_str), "\n";

// If this is an integer, increment it by four
if (is_int($an_int)) {
    $an_int += 4;
}
var_dump($an_int);

// If $a_bool is a string, print it out
if (is_string($a_bool)) {
    echo "String: $a_bool";
}
?>

    

ENTITY

bool
string
int(16)

[!NOTE] Prior to PHP 8.0.0, where the get_debug_type is not available, the gettype function can be used instead. However, it doesn't use the canonical type names.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

Arrays

For a list of all array functions, see the array functions chapter in the documentation.

An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.

Explanation of those data structures is beyond the scope of this manual, but at least one example is provided for each of them. For more information, look towards the considerable literature that exists about this broad topic.

Syntax

Specifying with array

An array can be created using the array language construct. It takes any number of comma-separated key =ENTITY value pairs as arguments.

array(

key

=ENTITY

value

,

key2

=ENTITY

value2

,

key3

=ENTITY

value3

, ... )

The comma after the last array element is optional and can be omitted. This is usually done for single-line arrays, i.e. array(1, 2) is preferred over array(1, 2, ). For multi-line arrays on the other hand the trailing comma is commonly used, as it allows easier addition of new elements at the end.

[!NOTE] A short array syntax exists which replaces array() with [].

A simple array

<?php
$array1 = array(
    "foo" => "bar",
    "bar" => "foo",
);

// Using the short array syntax
$array2 = [
    "foo" => "bar",
    "bar" => "foo",
];

var_dump($array1, $array2);
?>

    

The <key> can either be an int or a string. The <value> can be of any type.

Additionally the following <key> casts will occur:

If multiple elements in the array declaration use the same key, only the last one will be used as all others are overwritten.

Type Casting and Overwriting example

<?php
$array = array(
    1    => "a",
    "1"  => "b",
    1.5  => "c",
    true => "d",
);
var_dump($array);
?>

    

ENTITY

array(1) {
  [1]=>
  string(1) "d"
}

As all the keys in the above example are cast to 1, the value will be overwritten on every new element and the last assigned value "d" is the only one left over.

PHP arrays can contain int and string keys at the same time as PHP does not distinguish between indexed and associative arrays.

Mixed int and string keys

<?php
$array = array(
    "foo" => "bar",
    "bar" => "foo",
    100   => -100,
    -100  => 100,
);
var_dump($array);
?>

    

ENTITY

array(4) {
  ["foo"]=>
  string(3) "bar"
  ["bar"]=>
  string(3) "foo"
  [100]=>
  int(-100)
  [-100]=>
  int(100)
}

The <key> is optional. If it is not specified, PHP will use the increment of the largest previously used int key.

Indexed arrays without key

<?php
$array = array("foo", "bar", "hello", "world");
var_dump($array);
?>

    

ENTITY

array(4) {
  [0]=>
  string(3) "foo"
  [1]=>
  string(3) "bar"
  [2]=>
  string(5) "hello"
  [3]=>
  string(5) "world"
}

It is possible to specify the key only for some elements and leave it out for others:

Keys not on all elements

<?php
$array = array(
         "a",
         "b",
    6 => "c",
         "d",
);
var_dump($array);
?>

    

ENTITY

array(4) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [6]=>
  string(1) "c"
  [7]=>
  string(1) "d"
}

As you can see the last value "d" was assigned the key 7. This is because the largest integer key before that was 6.

Complex Type Casting and Overwriting example

This example includes all variations of type casting of keys and overwriting of elements.

<?php
$array = array(
    1    => 'a',
    '1'  => 'b', // the value "a" will be overwritten by "b"
    1.5  => 'c', // the value "b" will be overwritten by "c"
    -1 => 'd',
    '01'  => 'e', // as this is not an integer string it will NOT override the key for 1
    '1.5' => 'f', // as this is not an integer string it will NOT override the key for 1
    true => 'g', // the value "c" will be overwritten by "g"
    false => 'h',
    '' => 'i',
    null => 'j', // the value "i" will be overwritten by "j"
    'k', // value "k" is assigned the key 2. This is because the largest integer key before that was 1
    2 => 'l', // the value "k" will be overwritten by "l"
);

var_dump($array);
?>

    

ENTITY

array(7) {
  [1]=>
  string(1) "g"
  [-1]=>
  string(1) "d"
  ["01"]=>
  string(1) "e"
  ["1.5"]=>
  string(1) "f"
  [0]=>
  string(1) "h"
  [""]=>
  string(1) "j"
  [2]=>
  string(1) "l"
}

Negative index example

When assigning a negative integer key n, PHP will take care to assign the next key to n+1.

     
<?php
$array = [];

$array[-5] = 1;
$array[] = 2;

var_dump($array);
?>

    

ENTITY

array(2) {
  [-5]=>
  int(1)
  [-4]=>
  int(2)
}

[!WARNING] Prior to PHP 8.3.0, assigning a negative integer key n would assign the next key to 0, the previous example would therefore output:

array(2) {
  [-5]=>
  int(1)
  [0]=>
  int(2)
}

Accessing array elements with square bracket syntax

Array elements can be accessed using the array[key] syntax.

Accessing array elements

<?php
$array = array(
    "foo" => "bar",
    42    => 24,
    "multi" => array(
         "dimensional" => array(
             "array" => "foo"
         )
    )
);

var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
?>

    

ENTITY

string(3) "bar"
int(24)
string(3) "foo"

[!NOTE] Prior to PHP 8.0.0, square brackets and curly braces could be used interchangeably for accessing array elements (e.g. $array[42] and $array{42} would both do the same thing in the example above). The curly brace syntax was deprecated as of PHP 7.4.0 and no longer supported as of PHP 8.0.0.

Array dereferencing

<?php
function getArray() {
    return array(1, 2, 3);
}

$secondElement = getArray()[1];

var_dump($secondElement);
?>

    

[!NOTE] Attempting to access an array key which has not been defined is the same as accessing any other undefined variable: an E_WARNING-level error message (E_NOTICE-level prior to PHP 8.0.0) will be issued, and the result will be ENTITY.

[!NOTE] Array dereferencing a scalar value which is not a string yields ENTITY. Prior to PHP 7.4.0, that did not issue an error message. As of PHP 7.4.0, this issues E_NOTICE; as of PHP 8.0.0, this issues E_WARNING.

Creating/modifying with square bracket syntax

An existing array can be modified by explicitly setting values in it.

This is done by assigning values to the array, specifying the key in brackets. The key can also be omitted, resulting in an empty pair of brackets ([]).

$arr[

key

] =

value

; $arr[] =

value

; //

key

may be an

int

or

string

//

value

may be any value of any type

If $arr doesn't exist yet or is set to ENTITY or ENTITY, it will be created, so this is also an alternative way to create an array. This practice is however discouraged because if $arr already contains some value (e.g. string from request variable) then this value will stay in place and [] may actually stand for string access operator. It is always better to initialize a variable by a direct assignment.

[!NOTE] As of PHP 7.1.0, applying the empty index operator on a string throws a fatal error. Formerly, the string was silently converted to an array.

[!NOTE] As of PHP 8.1.0, creating a new array from ENTITY value is deprecated. Creating a new array from ENTITY and undefined values is still allowed.

To change a certain value, assign a new value to that element using its key. To remove a key/value pair, call the unset function on it.

Using Square Brackets with Arrays

<?php
$arr = array(5 => 1, 12 => 2);

$arr[] = 56;    // This is the same as $arr[13] = 56;
                // at this point of the script

$arr["x"] = 42; // This adds a new element to
                // the array with key "x"

unset($arr[5]); // This removes the element from the array

var_dump($arr);

unset($arr);    // This deletes the whole array

var_dump($arr);
?>

    

[!NOTE] If no key is specified, the key will be the maximum existing integer index + 1. If the array has no positive integer indices, the key will be 0. As of PHP 8.3.0, it can also be a negative integer.

Note that the maximum integer key used for this need not currently exist in the array. It need only have existed in the array at some time since the last time the array was re-indexed. The following example illustrates:

<?php
// Create a simple array.
$array = array(1, 2, 3, 4, 5);
print_r($array);

// Now delete every item, but leave the array itself intact:
foreach ($array as $i => $value) {
    unset($array[$i]);
}
print_r($array);

// Append an item (note that the new key is 5, instead of 0).
$array[] = 6;
print_r($array);

// Re-index:
$array = array_values($array);
$array[] = 7;
print_r($array);
?>

     

ENTITY

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
)
Array
(
)
Array
(
    [5] => 6
)
Array
(
    [0] => 6
    [1] => 7
)

Array destructuring

Arrays can be destructured using the [] (as of PHP 7.1.0) or list language constructs. These constructs can be used to destructure an array into distinct variables.

Array Destructuring

<?php
$source_array = ['foo', 'bar', 'baz'];

[$foo, $bar, $baz] = $source_array;

echo $foo, PHP_EOL;    // prints "foo"
echo $bar, PHP_EOL;    // prints "bar"
echo $baz, PHP_EOL;    // prints "baz"
?>

    

Array destructuring can be used in ENTITY to destructure a multi-dimensional array while iterating over it.

Array Destructuring in Foreach

<?php
$source_array = [
    [1, 'John'],
    [2, 'Jane'],
];

foreach ($source_array as [$id, $name]) {
    echo "{$id}: '{$name}'\n";
}
?>

    

Array elements will be ignored if the variable is not provided. Array destructuring always starts at index 0.

Ignoring Elements

<?php
$source_array = ['foo', 'bar', 'baz'];

// Assign the element at index 2 to the variable $baz
[, , $baz] = $source_array;

echo $baz;    // prints "baz"
?>

    

As of PHP 7.1.0, associative arrays can be destructured too. This also allows for easier selection of the right element in numerically indexed arrays as the index can be explicitly specified.

Destructuring Associative Arrays

<?php
$source_array = ['foo' => 1, 'bar' => 2, 'baz' => 3];

// Assign the element at index 'baz' to the variable $three
['baz' => $three] = $source_array;

echo $three, PHP_EOL;  // prints 3

$source_array = ['foo', 'bar', 'baz'];

// Assign the element at index 2 to the variable $baz
[2 => $baz] = $source_array;

echo $baz, PHP_EOL;    // prints "baz"
?>

    

Array destructuring can be used for easy swapping of two variables.

Swapping Two Variable

<?php
$a = 1;
$b = 2;

[$b, $a] = [$a, $b];

echo $a, PHP_EOL;    // prints 2
echo $b, PHP_EOL;    // prints 1
?>

    

[!NOTE] The spread operator (...) is not supported in assignments.

[!NOTE] Attempting to access an array key which has not been defined is the same as accessing any other undefined variable: an E_WARNING-level error message (E_NOTICE-level prior to PHP 8.0.0) will be issued, and the result will be ENTITY.

[!NOTE] Destructuring a scalar value assigns ENTITY to all variables.

Useful functions

There are quite a few useful functions for working with arrays. See the array functions section.

[!NOTE] The unset function allows removing keys from an array. Be aware that the array will not be reindexed. If a true "remove and shift" behavior is desired, the array can be reindexed using the array_values function.

Unsetting Intermediate Elements

<?php
$a = array(1 => 'one', 2 => 'two', 3 => 'three');

/* will produce an array that would have been defined as
   $a = array(1 => 'one', 3 => 'three');
   and NOT
   $a = array(1 => 'one', 2 =>'three');
*/
unset($a[2]);
var_dump($a);

$b = array_values($a);
// Now $b is array(0 => 'one', 1 =>'three')
var_dump($b);
?>

    

The ENTITY control structure exists specifically for arrays. It provides an easy way to traverse an array.

Array do's and don'ts

Why is $foo[bar] wrong?

Always use quotes around a string literal array index. For example, $foo['bar'] is correct, while $foo[bar] is not. But why? It is common to encounter this kind of syntax in old scripts:

<?php
$foo[bar] = 'enemy';
echo $foo[bar];
// etc
?>

    

This is wrong, but it works. The reason is that this code has an undefined constant (bar) rather than a string ('bar' - notice the quotes). It works because PHP automatically converts a bare string (an unquoted string which does not correspond to any known symbol) into a string which contains the bare string. For instance, if there is no defined constant named bar, then PHP will substitute in the string 'bar' and use that.

[!WARNING] The fallback to treat an undefined constant as bare string issues an error of level E_NOTICE. This has been deprecated as of PHP 7.2.0, and issues an error of level E_WARNING. As of PHP 8.0.0, it has been removed and throws an Error exception.

This does not mean to always quote the key. Do not quote keys which are constants or variables, as this will prevent PHP from interpreting them.

Key Quoting

<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('html_errors', false);

// Simple array:
$array = array(1, 2);
$count = count($array);

for ($i = 0; $i < $count; $i++) {
    echo "\nChecking $i: \n";
    echo "Bad: " . $array['$i'] . "\n";
    echo "Good: " . $array[$i] . "\n";
    echo "Bad: {$array['$i']}\n";
    echo "Good: {$array[$i]}\n";
}
?>

     

ENTITY

Checking 0:
Notice: Undefined index:  $i in /path/to/script.html on line 9
Bad:
Good: 1
Notice: Undefined index:  $i in /path/to/script.html on line 11
Bad:
Good: 1

Checking 1:
Notice: Undefined index:  $i in /path/to/script.html on line 9
Bad:
Good: 2
Notice: Undefined index:  $i in /path/to/script.html on line 11
Bad:
Good: 2

More examples to demonstrate this behaviour:

More Examples

<?php
// Show all errors
error_reporting(E_ALL);

$arr = array('fruit' => 'apple', 'veggie' => 'carrot');

// Correct
echo $arr['fruit'], PHP_EOL;  // apple
echo $arr['veggie'], PHP_EOL; // carrot

// Incorrect. This does not work and throws a PHP Error because
// of an undefined constant named fruit
//
// Error: Undefined constant "fruit"
try {
    echo $arr[fruit];
} catch (Error $e) {
    echo get_class($e), ': ', $e->getMessage(), PHP_EOL;
}

// This defines a constant to demonstrate what's going on.  The value 'veggie'
// is assigned to a constant named fruit.
define('fruit', 'veggie');

// Notice the difference now
echo $arr['fruit'], PHP_EOL;  // apple
echo $arr[fruit], PHP_EOL;    // carrot

// The following is okay, as it's inside a string. Constants are not looked for
// within strings, so no error occurs here
echo "Hello $arr[fruit]", PHP_EOL;      // Hello apple

// With one exception: braces surrounding arrays within strings allows constants
// to be interpreted
echo "Hello {$arr[fruit]}", PHP_EOL;    // Hello carrot
echo "Hello {$arr['fruit']}", PHP_EOL;  // Hello apple

// Concatenation is another option
echo "Hello " . $arr['fruit'], PHP_EOL; // Hello apple
?>

    
<?php
// This will not work, and will result in a parse error, such as:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'
// This of course applies to using superglobals in strings as well
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";
?>

    

As stated in the syntax section, what's inside the square brackets ('[' and ']') must be an expression. This means that code like this works:

<?php
echo $arr[somefunc($bar)];
?>

    

This is an example of using a function return value as the array index. PHP also knows about constants:

<?php
$error_descriptions[E_ERROR]   = "A fatal error has occurred";
$error_descriptions[E_WARNING] = "PHP issued a warning";
$error_descriptions[E_NOTICE]  = "This is just an informal notice";
?>

    

Note that E_ERROR is also a valid identifier, just like bar in the first example. But the last example is in fact the same as writing:

<?php
$error_descriptions[1] = "A fatal error has occurred";
$error_descriptions[2] = "PHP issued a warning";
$error_descriptions[8] = "This is just an informal notice";
?>

    

because E_ERROR equals 1, etc.

So why is it bad then?

At some point in the future, the PHP team might want to add another constant or keyword, or a constant in other code may interfere. For example, it is already wrong to use the words empty and default this way, since they are reserved keywords.

[!NOTE] To reiterate, inside a double-quoted string, it's valid to not surround array indexes with quotes so "$foo[bar]" is valid. See the above examples for details on why as well as the section on variable parsing in strings.

Converting to array

For any of the types int, float, string, bool and resource, converting a value to an array results in an array with a single element with index zero and the value of the scalar which was converted. In other words, (array) $scalarValue is exactly the same as array($scalarValue).

If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are inaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have NUL bytes on either side. Uninitialized typed properties are silently discarded.

Converting to an Array

    
<?php

class A {
    private $B;
    protected $C;
    public $D;
    function __construct()
    {
        $this->{1} = null;
    }
}

var_export((array) new A());
?>

   

ENTITY

array (
  '' . "\0" . 'A' . "\0" . 'B' => NULL,
  '' . "\0" . '*' . "\0" . 'C' => NULL,
  'D' => NULL,
  1 => NULL,
)

These NUL can result in some unexpected behaviour:

Casting an Object to an Array

<?php

class A {
    private $A; // This will become '\0A\0A'
}

class B extends A {
    private $A; // This will become '\0B\0A'
    public $AA; // This will become 'AA'
}

var_dump((array) new B());
?>

   

ENTITY

array(3) {
  ["BA"]=>
  NULL
  ["AA"]=>
  NULL
  ["AA"]=>
  NULL
}

ENTITY

array(3) {
  ["AA"]=>
  NULL
  ["BA"]=>
  NULL
  ["AA"]=>
  NULL
}

The above will appear to have two keys named 'AA', although one of them is actually named '\0A\0A'.

Converting ENTITY to an array results in an empty array.

Comparing

It is possible to compare arrays with the array_diff function and with array operators.

Array unpacking

An array prefixed by ... will be expanded in place during array definition. Only arrays and objects which implement Traversable can be expanded. Array unpacking with ... is available as of PHP 7.4.0. This is also called the spread operator.

It's possible to expand multiple times, and add normal elements before or after the ... operator:

Simple array unpacking

<?php
// Using short array syntax.
// Also, works with array() syntax.
$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; // [1, 2, 3]
$arr3 = [0, ...$arr1]; // [0, 1, 2, 3]
$arr4 = [...$arr1, ...$arr2, 111]; // [1, 2, 3, 1, 2, 3, 111]
$arr5 = [...$arr1, ...$arr1]; // [1, 2, 3, 1, 2, 3]

function getArr() {
  return ['a', 'b'];
}
$arr6 = [...getArr(), 'c' => 'd']; // ['a', 'b', 'c' => 'd']

var_dump($arr1, $arr2, $arr3, $arr4, $arr5, $arr6);
?>

    

Unpacking an array with the ... operator follows the semantics of the array_merge function. That is, later string keys overwrite earlier ones and integer keys are renumbered:

Array unpacking with duplicate key

<?php
// string key
$arr1 = ["a" => 1];
$arr2 = ["a" => 2];
$arr3 = ["a" => 0, ...$arr1, ...$arr2];
var_dump($arr3); // ["a" => 2]

// integer key
$arr4 = [1, 2, 3];
$arr5 = [4, 5, 6];
$arr6 = [...$arr4, ...$arr5];
var_dump($arr6); // [1, 2, 3, 4, 5, 6]
// Which is [0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6]
// where the original integer keys have not been retained.
?>

    

[!NOTE] Keys that are neither integers nor strings throw a TypeError. Such keys can only be generated by a Traversable object.

[!NOTE] Prior to PHP 8.1, unpacking an array which has a string key is not supported:

<?php

$arr1 = [1, 2, 3];
$arr2 = ['a' => 4];
$arr3 = [...$arr1, ...$arr2];
// Fatal error: Uncaught Error: Cannot unpack array with string keys in example.php:5

$arr4 = [1, 2, 3];
$arr5 = [4, 5];
$arr6 = [...$arr4, ...$arr5]; // works. [1, 2, 3, 4, 5]
?>

    

Examples

The array type in PHP is very versatile. Here are some examples:

Array Versatility

<?php
// This:
$a = array( 'color' => 'red',
            'taste' => 'sweet',
            'shape' => 'round',
            'name'  => 'apple',
            4        // key will be 0
          );

$b = array('a', 'b', 'c');

var_dump($a, $b);

// . . .is completely equivalent with this:
$a = array();
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name']  = 'apple';
$a[]        = 4;        // key will be 0

$b = array();
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';

// After the above code is executed, $a will be the array
// array('color' => 'red', 'taste' => 'sweet', 'shape' => 'round',
// 'name' => 'apple', 0 => 4), and $b will be the array
// array(0 => 'a', 1 => 'b', 2 => 'c'), or simply array('a', 'b', 'c').

var_dump($a, $b);
?>

   

Using array()

<?php
// Array as (property-)map
$map = array( 'version'    => 4,
              'OS'         => 'Linux',
              'lang'       => 'english',
              'short_tags' => true
            );
var_dump($map);

// strictly numerical keys
// this is the same as array(0 => 7, 1 => 8, ...)
$array = array( 7,
                8,
                0,
                156,
                -10
              );
var_dump($array);

$switching = array(         10, // key = 0
                    5    =>  6,
                    3    =>  7,
                    'a'  =>  4,
                            11, // key = 6 (maximum of integer-indices was 5)
                    '8'  =>  2, // key = 8 (integer!)
                    '02' => 77, // key = '02'
                    0    => 12  // the value 10 will be overwritten by 12
                  );
var_dump($switching);

// empty array
$empty = array();
var_dump($empty);
?>


   

Collection

<?php
$colors = array('red', 'blue', 'green', 'yellow');

foreach ($colors as $color) {
    echo "Do you like $color?\n";
}

?>

   

ENTITY

Do you like red?
Do you like blue?
Do you like green?
Do you like yellow?

Changing the values of the array directly is possible by passing them by reference.

Changing element in the loop

<?php
$colors = array('red', 'blue', 'green', 'yellow');

foreach ($colors as &$color) {
    $color = mb_strtoupper($color);
}
unset($color); /* ensure that following writes to
$color will not modify the last array element */

print_r($colors);
?>

   

ENTITY

Array
(
    [0] => RED
    [1] => BLUE
    [2] => GREEN
    [3] => YELLOW
)

This example creates a one-based array.

One-based index

<?php
$firstquarter = array(1 => 'January', 'February', 'March');
print_r($firstquarter);
?>

   

ENTITY

Array
(
    [1] => January
    [2] => February
    [3] => March
)

Filling an array

<?php
// fill an array with all items from a directory
$handle = opendir('.');
while (false !== ($file = readdir($handle))) {
    $files[] = $file;
}
closedir($handle);

var_dump($files);
?>

   

Arrays are ordered. The order can be changed using various sorting functions. See the array functions section for more information. The count function can be used to count the number of items in an array.

Sorting an array

<?php
sort($files);
print_r($files);
?>

   

Because the value of an array can be anything, it can also be another array. This enables the creation of recursive and multi-dimensional arrays.

Recursive and multi-dimensional arrays

<?php
$fruits = array ( "fruits"  => array ( "a" => "orange",
                                       "b" => "banana",
                                       "c" => "apple"
                                     ),
                  "numbers" => array ( 1,
                                       2,
                                       3,
                                       4,
                                       5,
                                       6
                                     ),
                  "holes"   => array (      "first",
                                       5 => "second",
                                            "third"
                                     )
                );
var_dump($fruits);

// Some examples to address values in the array above
echo $fruits["holes"][5];    // prints "second"
echo $fruits["fruits"]["a"]; // prints "orange"
unset($fruits["holes"][0]);  // remove "first"

// Create a new multi-dimensional array
$juices["apple"]["green"] = "good";
var_dump($juices);
?>

   

Array assignment always involves value copying. Use the reference operator to copy an array by reference.

Array Copying

<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
             // $arr1 is still array(2, 3)

$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same

var_dump($arr1, $arr2, $arr3);
?>

   

Booleans

The bool type only has two values, and is used to express a truth value. It can be either ENTITY or ENTITY.

Syntax

To specify a bool literal, use the constants ENTITY or ENTITY. Both are case-insensitive.

<?php

$foo = True; // assign the value TRUE to $foo

var_dump($foo); // bool(true)
?>

   

Typically, the result of an operator which returns a bool value is passed on to a control structure.

<?php

$action = "show_version";
$show_separators = true;

// == is an operator which tests
// equality and returns a boolean
if ($action == "show_version") {
    echo "The version is 1.23";
}

// this is not necessary...
if ($show_separators == TRUE) {
    echo "<hr>\n";
}

// ...because this can be used with exactly the same meaning:
if ($show_separators) {
    echo "<hr>\n";
}
?>

   

Converting to boolean

To explicitly convert a value to bool, use the (bool) cast. Generally this is not necessary because when a value is used in a logical context it will be automatically interpreted as a value of type bool. For more information see the Type Juggling page.

When converting to bool, the following values are considered ENTITY:

Every other value is considered ENTITY (including resource and NAN).

[!WARNING] -1 is considered ENTITY, like any other non-zero (whether negative or positive) number!

Casting to Boolean

<?php
var_dump((bool) "");        // bool(false)
var_dump((bool) "0");       // bool(false)
var_dump((bool) 1);         // bool(true)
var_dump((bool) -2);        // bool(true)
var_dump((bool) "foo");     // bool(true)
var_dump((bool) 2.3e5);     // bool(true)
var_dump((bool) array(12)); // bool(true)
var_dump((bool) array());   // bool(false)
var_dump((bool) "false");   // bool(true)
?>

   

Callables

A callable is a reference to a function or method that is passed to another function as an argument. They are represented with the callable type declaration.

<?php
function foo(callable $callback) {
    $callback();
}
?>

  

Some functions accept callback functions as a parameter, e.g. array_map, usort, or preg_replace_callback.

Creation of callables

A callable is a type that represents something that can be invoked. Callables can be passed as arguments to functions or methods which expect a callback parameter or they can be invoked directly. The callable type cannot be used as a type declaration for class properties. Instead, use a Closure type declaration.

Callables can be created in several different ways:

A Closure object can be created using anonymous function syntax, arrow function syntax, first-class callable syntax, or the Closure::fromCallable method.

[!NOTE] The first-class callable syntax is only available as of PHP 8.1.0.

Callback example using a Closure

<?php
// Using anonymous function syntax
$double1 = function ($a) {
    return $a * 2;
};

// Using first-class callable syntax
function double_function($a) {
    return $a * 2;
}
$double2 = double_function(...);

// Using arrow function syntax
$double3 = fn($a) => $a * 2;

// Using Closure::fromCallable
$double4 = Closure::fromCallable('double_function');

// Use the closure as a callback here to
// double the size of each element in our range
$new_numbers = array_map($double1, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double2, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double3, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double4, range(1, 5));
print implode(' ', $new_numbers);

?>

   

ENTITY

2 4 6 8 10
2 4 6 8 10
2 4 6 8 10
2 4 6 8 10

A callable can also be a string containing the name of a function or a static method. Any built-in or user-defined function can be used, except language constructs such as: array, echo, empty, eval, isset, list, print or unset.

Static class methods can be used without instantiating an object of that class by either creating an array with the class name at index 0 and the method name at index 1, or by using the special syntax with the scope resolution operator ::, as in 'ClassName::methodName'.

A method of an instantiated object can be a callable when provided as an array with the object at index 0 and the method name at index 1.

The main difference between a Closure object and the callable type is that a Closure object is scope-independent and can always be invoked, whereas a callable type may be scope-dependent and may not be directly invoked. Closure is the preferred way to create callables. As of PHP 8.5.0, Closure is a proper subtype of callable.

[!NOTE] While Closure objects are bound to the scope where they are created, callables referencing class methods as strings or arrays are resolved in the scope where they are called. To create a callable from a private or protected method, which can then be invoked from outside the class scope, use Closure::fromCallable or the first-class callable syntax.

PHP allows the creation of callables which can be used as a callback argument but cannot be called directly. These are context-dependent callables which reference a class method in the inheritance hierarchy of a class, e.g. 'parent::method' or ["static", "method"].

[!NOTE] As of PHP 8.2.0, context-dependent callables are deprecated. Remove the context dependency by replacing 'parent::method' with parent::class . '::method' or use the first-class callable syntax.

Calling various types of callables with call_user_func

<?php

// An example callback function
function my_callback_function() {
    echo 'hello world!', PHP_EOL;
}

// An example callback method
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!', PHP_EOL;
    }
}

// Type 1: Simple callback
call_user_func('my_callback_function');

// Type 2: Static class method call
call_user_func(['MyClass', 'myCallbackMethod']);

// Type 3: Object method call
$obj = new MyClass();
call_user_func([$obj, 'myCallbackMethod']);

// Type 4: Static class method call
call_user_func('MyClass::myCallbackMethod');

// Type 5: Static class method call using ::class keyword
call_user_func([MyClass::class, 'myCallbackMethod']);

// Type 6: Relative static class method call
class A {
    public static function who() {
        echo 'A', PHP_EOL;
    }
}

class B extends A {
    public static function who() {
        echo 'B', PHP_EOL;
    }
}

call_user_func(['B', 'parent::who']); // deprecated as of PHP 8.2.0

// Type 7: Objects implementing __invoke can be used as callables
class C {
    public function __invoke($name) {
        echo 'Hello ', $name;
    }
}

$c = new C();
call_user_func($c, 'PHP!');
?>

   

ENTITY

hello world!
Hello World!
Hello World!
Hello World!
Hello World!

Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 44
A
Hello PHP!

ENTITY

Type declarations

Type declarations can be added to function arguments, return values, as of PHP 7.4.0, class properties, and as of PHP 8.3.0, class constants. They ensure that the value is of the specified type at call time, otherwise a TypeError is thrown.

Every single type that PHP supports, with the exception of resource, can be used within a user-land type declaration. This page contains a changelog of availability of the different types and documentation about usage of them in type declarations.

[!NOTE] When a class implements an interface method or reimplements a method which has already been defined by a parent class, it has to be compatible with the aforementioned definition. A method is compatible if it follows the variance rules.

ENTITY

ENTITY ENTITY
8.3.0 Support for class, interface, trait, and enum constant typing has been added.
8.2.0 Support for DNF types has been added.
8.2.0 Support for the literal type true has been added.
8.2.0 The types null and false can now be used standalone.
8.1.0 Support for intersection types has been added.
8.1.0 Returning by reference from a void function is now deprecated.
8.1.0 Support for the return only type never has been added.
8.0.0 Support for mixed has been added.
8.0.0 Support for the return only type static has been added.
8.0.0 Support for union types has been added.
7.4.0 Support for class properties typing has been added.
7.2.0 Support for object has been added.
7.1.0 Support for iterable has been added.
7.1.0 Support for void has been added.
7.1.0 Support for nullable types has been added.

Atomic Types Usage Notes

Atomic types have straightforward behaviour with some minor caveats which are described in this section.

Scalar types

[!WARNING] Name aliases for scalar types (bool, int, float, string) are not supported. Instead, they are treated as class or interface names. For example, using boolean as a type declaration will require the value to be an ENTITY the class or interface boolean, rather than of type bool:

<?php
    function test(boolean $param) {}
    test(true);
?>

     

ENTITY

Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2

Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2
Stack trace:
#0 -(3): test(true)
#1 {main}
  thrown in - on line 2

void

[!NOTE] Returning by reference from a void function is deprecated as of PHP 8.1.0, because such a function is contradictory. Previously, it already emitted the following E_NOTICE when called: Only variable references should be returned by reference.

<?php
function &test(): void {}
?>

      

Callable types

This type cannot be used as a class property type declaration.

[!NOTE] It is not possible to specify the signature of the function.

Type declarations on pass-by-reference Parameters

If a pass-by-reference parameter has a type declaration, the type of the variable is only checked on function entry, at the beginning of the call, but not when the function returns. This means that a function can change the type of the variable passed by reference.

Typed pass-by-reference Parameters

<?php
function array_baz(array &$param)
{
    $param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>

    

ENTITY

int(1)

Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2
Stack trace:
#0 -(9): array_baz(1)
#1 {main}
  thrown in - on line 2

Composite Types Usage Notes

Composite type declarations are subject to a couple of restrictions and will perform a redundancy check at compile time to prevent simple bugs.

[!CAUTION] Prior to PHP 8.2.0, and the introduction of DNF types, it was not possible to combine intersection types with union types.

Union types

[!WARNING] It is not possible to combine the two singleton types false and true together in a union type. Use bool instead.

[!CAUTION] Prior to PHP 8.2.0, as false and null could not be used as standalone types, a union type comprised of only these types was not permitted. This comprises the following types: false, false|null, and ?false.

Nullable type syntactic sugar

A single base type declaration can be marked nullable by prefixing the type with a question mark (?). Thus ?T and T|null are identical.

[!NOTE] This syntax is supported as of PHP 7.1.0, and predates generalized union types support.

[!NOTE] It is also possible to achieve nullable arguments by making ENTITY the default value. This is not recommended because if the default value is changed in a child class a type compatibility violation will be raised as the null type will need to be added to the type declaration. This behavior is also deprecated since PHP 8.4.

Old way to make arguments nullable

<?php
class C {}

function f(C $c = null) {
    var_dump($c);
}

f(new C);
f(null);
?>

      

ENTITY

object(C)#1 (0) {
}
NULL

Duplicate and redundant types

To catch simple bugs in composite type declarations, redundant types that can be detected without performing class loading will result in a compile-time error. This includes:

[!NOTE] This does not guarantee that the type is “minimal”, because doing so would require loading all used class types.

For example, if A and B are class aliases, then A|B remains a legal union type, even though it could be reduced to either A or B. Similarly, if class B extends A {}, then A|B is also a legal union type, even though it could be reduced to just A.

<?php
function foo(): int|INT {} // Disallowed
function foo(): bool|false {} // Disallowed
function foo(): int&Traversable {} // Disallowed
function foo(): self&Traversable {} // Disallowed

use A as B;
function foo(): A|B {} // Disallowed ("use" is part of name resolution)
function foo(): A&B {} // Disallowed ("use" is part of name resolution)

class_alias('X', 'Y');
function foo(): X|Y {} // Allowed (redundancy is only known at runtime)
function foo(): X&Y {} // Allowed (redundancy is only known at runtime)
?>

     

ENTITY

Basic class type declaration

<?php
class C {}
class D extends C {}

// This doesn't extend C.
class E {}

function f(C $c) {
    echo get_class($c)."\n";
}

f(new C);
f(new D);
f(new E);
?>

   

ENTITY

C
D

Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
  thrown in - on line 8

Basic interface type declaration

<?php
interface I { public function f(); }
class C implements I { public function f() {} }

// This doesn't implement I.
class E {}

function f(I $i) {
    echo get_class($i)."\n";
}

f(new C);
f(new E);
?>

   

ENTITY

C

Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, E given, called in - on line 13 and defined in -:8
Stack trace:
#0 -(13): f(Object(E))
#1 {main}
  thrown in - on line 8

Basic return type declaration

<?php
function sum($a, $b): float {
    return $a + $b;
}

// Note that a float will be returned.
var_dump(sum(1, 2));
?>

   

ENTITY

float(3)

Returning an object

<?php
class C {}

function getC(): C {
    return new C;
}

var_dump(getC());
?>

   

ENTITY

object(C)#1 (0) {
}

Nullable argument type declaration

    
<?php
class C {}

function f(?C $c) {
    var_dump($c);
}

f(new C);
f(null);
?>

   

ENTITY

object(C)#1 (0) {
}
NULL

Nullable return type declaration

    
<?php
function get_item(): ?string {
    if (isset($_GET['item'])) {
        return $_GET['item'];
    } else {
        return null;
    }
}
?>

   

Class property type declaration

<?php
class User {
    public static string $foo = 'foo';

    public int $id;
    public string $username;

    public function __construct(int $id, string $username) {
        $this->id = $id;
        $this->username = $username;
    }
}
?>

   

Strict typing

By default, PHP will coerce values of the wrong type into the expected scalar type declaration if possible. For example, a function that is given an int for a parameter that expects a string will get a variable of type string.

It is possible to enable strict mode on a per-file basis. In strict mode, only a value corresponding exactly to the type declaration will be accepted, otherwise a TypeError will be thrown. The only exception to this rule is that an int value will pass a float type declaration.

[!WARNING] Function calls from within internal functions will not be affected by the strict_types declaration.

To enable strict mode, the ENTITY statement is used with the strict_types declaration:

[!NOTE] Strict typing applies to function calls made from within the file with strict typing enabled, not to the functions declared within that file. If a file without strict typing enabled makes a call to a function that was defined in a file with strict typing, the caller's preference (coercive typing) will be respected, and the value will be coerced.

[!NOTE] Strict typing is only defined for scalar type declarations.

Strict typing for arguments values

<?php
declare(strict_types=1);

function sum(int $a, int $b) {
    return $a + $b;
}

var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>

   

ENTITY

int(3)

Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
  thrown in - on line 4

Coercive typing for argument values

<?php
function sum(int $a, int $b) {
    return $a + $b;
}

var_dump(sum(1, 2));

// These will be coerced to integers: note the output below!
var_dump(sum(1.5, 2.5));
?>

   

ENTITY

int(3)
int(3)

Strict typing for return values

<?php
declare(strict_types=1);

function sum($a, $b): int {
    return $a + $b;
}

var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>

   

ENTITY

int(3)

Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5
Stack trace:
#0 -(9): sum(1, 2.5)
#1 {main}
  thrown in - on line 5

Enumerations

Basic Enumerations

Enumerations are a restricting layer on top of classes and class constants, intended to provide a way to define a closed set of possible values for a type.

<?php
enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

function do_stuff(Suit $s)
{
    // ...
}

do_stuff(Suit::Spades);
?>

   

For a full discussion, see the Enumerations chapter.

Casting

If an enum is converted to an object, it is not modified. If an enum is converted to an array, an array with a single name key (for Pure enums) or an array with both name and value keys (for Backed enums) is created. All other cast types will result in an error.

Floating-point numbers

Floating-point numbers (also known as "floats", "doubles", or "real numbers") can be specified using any of the following syntaxes:

<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
$d = 1_234.567; // as of PHP 7.4.0
?>

  

Formally as of PHP 7.4.0 (previously, underscores have not been allowed):

LNUM          [0-9]+(_[0-9]+)*
DNUM          ({LNUM}?"."{LNUM}) | ({LNUM}"."{LNUM}?)
EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})

The size of a float is platform-dependent, although a maximum of approximately 1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).

[!WARNING] Floating-point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non-elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.

Additionally, rational numbers that are exactly representable as floating-point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating-point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....

So never trust floating-point number results to the last digit, and do not compare floating-point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.

For a "simple" explanation, see the floating point guide that's also titled "Why don’t my numbers add up?"

Converting to float

From strings

If the string is numeric or leading numeric then it will resolve to the corresponding float value, otherwise it is converted to zero (0).

From other types

For values of other types, the conversion is performed by converting the value to int first and then to float. See Converting to integer for more information.

[!NOTE] As certain types have undefined behavior when converting to int, this is also the case when converting to float.

Comparing floats

As noted in the warning above, testing floating-point values for equality is problematic, due to the way that they are represented internally. However, there are ways to make comparisons of floating-point values that work around these limitations.

To test floating-point values for equality, an upper bound on the relative error due to rounding is used. This value is known as the machine epsilon, or unit roundoff, and is the smallest acceptable difference in calculations.

$a and $b are equal to 5 digits of precision.

Comparing Floats

<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if (abs($a - $b) < $epsilon) {
    echo "true";
}
?>

   

NaN

Some numeric operations can result in a value represented by the constant NAN. This result represents an undefined or unrepresentable value in floating-point calculations. Any loose or strict comparisons of this value against any other value, including itself, but except ENTITY, will have a result of ENTITY.

Because NAN represents any number of different values, NAN should not be compared to other values, including itself, and instead should be checked for using is_nan.

Integers

An int is a number of the set ℤ = {..., -2, -1, 0, 1, 2, ...}.

ENTITY

Floating-point numbers, Arbitrary precision / BCMath, Arbitrary length integer / GMP

Syntax

Ints can be specified in decimal (base 10), hexadecimal (base 16), octal (base 8) or binary (base 2) notation. The negation operator can be used to denote a negative int.

To use octal notation, precede the number with a 0 (zero). As of PHP 8.1.0, octal notation can also be preceded with 0o or 0O. To use hexadecimal notation, precede the number with 0x. To use binary notation, precede the number with 0b.

As of PHP 7.4.0, integer literals may contain underscores (_) between digits, for better readability of literals. These underscores are removed by PHP's scanner.

Integer literals

<?php
$a = 1234; // decimal number
$a = 0123; // octal number (equivalent to 83 decimal)
$a = 0o123; // octal number (as of PHP 8.1.0)
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)
$a = 0b11111111; // binary number (equivalent to 255 decimal)
$a = 1_234_567; // decimal number (as of PHP 7.4.0)
?>

   

Formally, the structure for int literals is as of PHP 8.1.0 (previously, the 0o or 0O octal prefixes were not allowed, and prior to PHP 7.4.0 the underscores were not allowed):

decimal     : [1-9][0-9]*(_[0-9]+)*
            | 0

hexadecimal : 0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*

octal       : 0[oO]?[0-7]+(_[0-7]+)*

binary      : 0[bB][01]+(_[01]+)*

integer     : decimal
            | hexadecimal
            | octal
            | binary

The size of an int is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18. PHP does not support unsigned ints. int size can be determined using the constant PHP_INT_SIZE, maximum value using the constant PHP_INT_MAX, and minimum value using the constant PHP_INT_MIN.

Integer overflow

If PHP encounters a number beyond the bounds of the int type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the int type will return a float instead.

Integer overflow

<?php
$large_number = 50000000000000000000;
var_dump($large_number);         // float(5.0E+19)

var_dump(PHP_INT_MAX + 1);       // 32-bit system: float(2147483648)
                                 // 64-bit system: float(9.2233720368548E+18)
?>

   

Integer division

There is no int division operator in PHP. To achieve this, use the intdiv function. 1/2 yields the float 0.5. The value can be cast to an int to round it towards zero, or the round function provides finer control over rounding.

Divisions

<?php
var_dump(25/7);         // float(3.5714285714286)
var_dump((int) (25/7)); // int(3)
var_dump(round(25/7));  // float(4)
?>

   

Converting to integer

To explicitly convert a value to int, use the (int) cast. However, in most cases the cast is not needed, since a value will be automatically converted if an operator, function or control structure requires an int argument. A value can also be converted to int with the intval function.

If a resource is converted to an int, then the result will be the unique resource number assigned to the resource by PHP at runtime.

See also Type Juggling.

From booleans

ENTITY will yield 0 (zero), and ENTITY will yield 1 (one).

From floating point numbers

When converting from float to int, the number will be rounded towards zero. As of PHP 8.1.0, a deprecation notice is emitted when implicitly converting a non-integral ENTITY to an ENTITY which loses precision.

Casting from Float

<?php

function foo($value): int {
  return $value;
}

var_dump(foo(8.1)); // "Deprecated: Implicit conversion from float 8.1 to int loses precision" as of PHP 8.1.0
var_dump(foo(8.1)); // 8 prior to PHP 8.1.0
var_dump(foo(8.0)); // 8 in both cases

var_dump((int) 8.1); // 8 in both cases
var_dump(intval(8.1)); // 8 in both cases
?>

    

If the float is beyond the boundaries of int (usually +/- 2.15e+9 = 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have enough precision to give an exact int result. As of PHP 8.5.0, an E_WARNING is emitted when a float that is not representable as an int is cast to one. Prior to PHP 8.5.0, no diagnostic at all was issued.

[!NOTE] NaN, Inf and -Inf will always be zero when cast to int. As of PHP 8.5.0, casting them to int emits an E_WARNING, as does casting NAN to any other type.

[!WARNING] Never cast an unknown fraction to int, as this can sometimes lead to unexpected results.

<?php
echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
?>

     

See also the warning about float precision.

From strings

If the string is numeric or leading numeric then it will resolve to the corresponding integer value, otherwise it is converted to zero (0).

From NULL

ENTITY is always converted to zero (0).

From other types

[!CAUTION] The behaviour of converting to int is undefined for other types. Do not rely on any observed behaviour, as it can change without notice.

Iterables

Iterable is a built-in compile-time type alias for array|Traversable. From its introduction in PHP 7.1.0 and prior to PHP 8.2.0, iterable was a built-in pseudo-type that acted as the aforementioned type alias and could be used as a type declaration. An iterable type can be used in ENTITY and with yield from within a generator.

[!NOTE] Functions declaring iterable as a return type may also be generators.

Iterable generator return type example

     
<?php

function gen(): iterable {
    yield 1;
    yield 2;
    yield 3;
}

foreach(gen() as $value) {
    echo $value, "\n";
}
?>

    

Mixed

The mixed type accepts every value. It is equivalent to the union type object|resource|array|string|float|int|bool|null. Available as of PHP 8.0.0.

mixed is, in type theory parlance, the top type, meaning every other type is a subtype of it.

Never

never is a return-only type indicating the function does not terminate. This means that it either calls exit, throws an exception, or is an infinite loop. Therefore, it cannot be part of a union type declaration. Available as of PHP 8.1.0.

A return statement in a never function is a compile-time error, even if the return would not be reached during execution. If control flow reaches the end of a never function without exiting, throwing an exception, or entering an infinite loop, a TypeError is thrown.

never is, in type theory parlance, the bottom type, meaning it is the subtype of every other type and can replace any other return type during inheritance.

NULL

The null type is PHP's unit type, i.e. it has only one value: ENTITY.

Undefined and unset variables resolve to the value ENTITY.

Syntax

There is only one value of type null, and that is the case-insensitive constant ENTITY.

<?php
$var = NULL;       
?>

   

Casting to ENTITY

ENTITY

Casting a variable to null using (unset) $var will not remove the variable or unset its value. It will only return a ENTITY value.

ENTITY

is_null, unset

Numeric strings

A PHP string is considered numeric if it can be interpreted as an int or a float.

Formally as of PHP 8.0.0:

WHITESPACES      \s*
LNUM             [0-9]+
DNUM             ([0-9]*[\.]{LNUM}) | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM    (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
INT_NUM_STRING   {WHITESPACES} [+-]? {LNUM} {WHITESPACES}
FLOAT_NUM_STRING {WHITESPACES} [+-]? ({DNUM} | {EXPONENT_DNUM}) {WHITESPACES}
NUM_STRING       ({INT_NUM_STRING} | {FLOAT_NUM_STRING})

PHP also has a concept of leading numeric strings. This is simply a string which starts like a numeric string followed by any characters.

[!NOTE] Any string that contains the letter E (case insensitive) bounded by numbers will be seen as a number expressed in scientific notation. This can produce unexpected results.

Scientific Notation Comparisons

<?php
var_dump("0D1" == "000"); // false, "0D1" is not scientific notation
var_dump("0E1" == "000"); // true, "0E1" is 0 * (10 ^ 1), or 0
var_dump("2E1" == "020"); // true, "2E1" is 2 * (10 ^ 1), or 20
?>

   

Strings used in numeric contexts

When a string needs to be evaluated as a number (e.g. arithmetic operations, int type declaration, etc.) the following steps are taken to determine the outcome:

  1. If the string is numeric, resolve to an int if the string is an integer numeric string and fits into the limits of the int type limits (as defined by PHP_INT_MIN and PHP_INT_MAX), otherwise resolve to a float.

  2. If the context allows leading numeric strings and the string is one, resolve to an int if the leading part of the string is an integer numeric string and fits into the limits of the int type limits (as defined by PHP_INT_MIN and PHP_INT_MAX), otherwise resolve to a float. Additionally an error of level E_WARNING is raised.

  3. If the string is not numeric, throw a TypeError.

Behavior prior to PHP 8.0.0

Prior to PHP 8.0.0, a string was considered numeric if it only had leading whitespaces. If it had trailing whitespaces then the string was considered to be leading numeric.

Prior to PHP 8.0.0, when a string was used in a numeric context it would perform the same steps as above with the following differences:

Prior to PHP 7.1.0, neither E_NOTICE nor E_WARNING was raised.

<?php
$foo = 1 + "10.5";                // $foo is float (11.5)
$foo = 1 + "-1.3e3";              // $foo is float (-1299)
$foo = 1 + "bob-1.3e3";           // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "bob3";                // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "10 Small Pigs";       // $foo is integer (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = "10.0 pigs " + 1;          // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = "10.0 pigs " + 1.0;        // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
?>

   

Objects

Object Initialization

To create a new object, use the new statement to instantiate a class:

Object Construction

<?php
class foo
{
    function do_foo()
    {
        echo "Doing foo.";
    }
}

$bar = new foo;
$bar->do_foo();
?>

   

For a full discussion, see the Classes and Objects chapter.

Converting to object

If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was ENTITY, the new instance will be empty. An array converts to an object with properties named by keys and with their corresponding values. Prior to PHP 7.2.0, numeric keys would have been inaccessible unless iterated.

Casting to an Object

<?php
$obj = (object) array('1' => 'foo');
var_dump(isset($obj->{'1'})); // outputs 'bool(true)'

// Deprecated as of PHP 8.1
var_dump(key($obj)); // outputs 'string(1) "1"'
?>

   

For any other value, a member variable named scalar will contain the value.

(object) cast

<?php
$obj = (object) 'ciao';
echo $obj->scalar;  // outputs 'ciao'
?>

   

Relative class types

These type declarations can only be used within classes.

self

The value must be an ENTITY the same class as the one in which the type declaration is used.

parent

The value must be an ENTITY a parent of the class in which the type declaration is used.

static

static is a return-only type which requires that the value returned must be an ENTITY the same class as the one the method is called in. Available as of PHP 8.0.0.

Resources

A resource is a special variable, holding a reference to an external resource. Resources are created and used by special functions. See the appendix for a listing of all these functions and the corresponding resource types.

See also the get_resource_type function.

Converting to resource

As resource variables hold special handles to opened files, database connections, image canvas areas and the like, converting to a resource makes no sense.

Freeing resources

Thanks to the reference-counting system being part of the Zend Engine, a resource with no more references to it is detected automatically, and it is freed by the garbage collector. For this reason, it is rarely necessary to free the memory manually.

[!NOTE] Persistent database links are an exception to this rule. They are not destroyed by the garbage collector. See the persistent connections section for more information.

Singleton types

Singleton types are those which allow only one value. PHP has support for two singleton types: false as of PHP 8.0.0 and true as of PHP 8.2.0.

[!WARNING] Prior to PHP 8.2.0, the false type could only be used as part of a union type.

[!NOTE] It is not possible to define custom singleton types. Consider using enumerations instead.

Strings

A string is a series of characters, where a character is the same as a byte. This means that PHP only supports a 256-character set, and hence does not offer native Unicode support. See details of the string type.

[!NOTE] On 32-bit builds, a string can be up to 2GB (2147483647 bytes) in length.

Syntax

A string literal can be specified in four different ways:

Single quoted

The simplest way to specify a string is to enclose it in single quotes (the character ').

To specify a literal single quote, escape it with a backslash (\). To specify a literal backslash, double it (\\). All other instances of backslash will be treated as a literal backslash: this means that the other escape sequences you might be used to, such as \r or \n, will be output literally as specified rather than having any special meaning.

[!NOTE] Unlike the double-quoted and heredoc syntaxes, variables and escape sequences for special characters will not be expanded when they occur in single quoted strings.

Syntax Variants

<?php
echo 'this is a simple string', PHP_EOL;

echo 'You can also have embedded newlines in
strings this way as it is
okay to do', PHP_EOL;

// Outputs: Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"', PHP_EOL;

// Outputs: You deleted C:\*.*?
echo 'You deleted C:\\*.*?', PHP_EOL;

// Outputs: You deleted C:\*.*?
echo 'You deleted C:\*.*?', PHP_EOL;

// Outputs: This will not expand: \n a newline
echo 'This will not expand: \n a newline', PHP_EOL;

// Outputs: Variables do not $expand $either
echo 'Variables do not $expand $either', PHP_EOL;
?>

    

Double quoted

If the string is enclosed in double-quotes ("), PHP will interpret the following escape sequences for special characters:

Sequence Meaning
\n linefeed (LF or 0x0A (10) in ASCII)
\r carriage return (CR or 0x0D (13) in ASCII)
\t horizontal tab (HT or 0x09 (9) in ASCII)
\v vertical tab (VT or 0x0B (11) in ASCII)
\e escape (ESC or 0x1B (27) in ASCII)
\f form feed (FF or 0x0C (12) in ASCII)
\\ backslash
\$ dollar sign
\" double-quote
\[0-7]{1,3} Octal: the sequence of characters matching the regular expression [0-7]{1,3} is a character in octal notation (e.g. "\101" === "A"), which silently overflows to fit in a byte (e.g. "\400" === "\000")
\x[0-9A-Fa-f]{1,2} Hexadecimal: the sequence of characters matching the regular expression [0-9A-Fa-f]{1,2} is a character in hexadecimal notation (e.g. "\x41" === "A")
\u{[0-9A-Fa-f]+} Unicode: the sequence of characters matching the regular expression [0-9A-Fa-f]+ is a Unicode codepoint, which will be output to the string as that codepoint's UTF-8 representation. The braces are required in the sequence. E.g. "\u{41}" === "A"

Escaped characters

As in single quoted strings, escaping any other character will result in the backslash being printed too.

The most important feature of double-quoted strings is the fact that variable names will be expanded. See string interpolation for details.

Heredoc

A third way to delimit strings is the heredoc syntax: ENTITYENTITYENTITY. After this operator, an identifier is provided, then a newline. The string itself follows, and then the same identifier again to close the quotation.

The closing identifier may be indented with spaces or tabs. Whitespace equal to the closing identifier's indentation is then removed from the beginning of every line in the heredoc string. Prior to PHP 7.3.0, the closing identifier must begin in the first column of the line.

Also, the closing identifier must follow the same naming rules as any other label in PHP: it must contain only alphanumeric characters and underscores, and must start with a non-digit character or underscore.

Basic Heredoc example as of PHP 7.3.0

<?php
// closing identifier not indented
echo <<<END
      a
     b
    c
\n
END;

// closing identifier indented with 3 spaces; 3 spaces stripped from each line
echo <<<END
      a
     b
    c
   END;

    

ENTITY

      a
     b
    c

   a
  b
 c

If the closing identifier is indented further than any lines of the body, then a ParseError will be thrown:

Closing identifier must not be indented further than any lines of the body

<?php
echo <<<END
  a
 b
c
   END;

    

ENTITY

Parse error: Invalid body indentation level (expecting an indentation level of at least 3) in example.php on line 4

If the closing identifier is indented, tabs can be used as well. However, tabs and spaces must not be intermixed. The indentation of the body and the closing identifier must use one or the other consistently. If tabs and spaces are mixed, then a ParseError will be thrown. These whitespace constraints have been included because mixing tabs and spaces for indentation is harmful to legibility.

Different indentation for body and closing identifier

<?php
// All of the following code does not work.

// different indentation for body (spaces) and ending marker (tabs)
{
    echo <<<END
     a
        END;
}

// mixing spaces and tabs in body
{
    echo <<<END
        a
     END;
}

// mixing spaces and tabs in ending marker
{
    echo <<<END
          a
         END;
}

    

ENTITY

Parse error: Invalid indentation - tabs and spaces cannot be mixed in example.php line 8

The closing identifier for the body string is not required to be followed by a semicolon or newline. For example, the following code is allowed as of PHP 7.3.0:

Continuing an expression after a closing identifier

<?php
$values = [<<<END
a
  b
    c
END, 'd e f'];
var_dump($values);

    

ENTITY

array(2) {
  [0] =>
  string(11) "a
  b
    c"
  [1] =>
  string(5) "d e f"
}

[!WARNING] If the closing identifier is found at the start of a line, then regardless of whether it is a part of another word, it is considered as the closing identifier and causes a ParseError.

Closing identifier in body of the string tends to cause ParseError

<?php
$values = [<<<END
a
b
END ING
END, 'd e f'];

     

ENTITY

Parse error: syntax error, unexpected identifier "ING", expecting "]" in example.php on line 5

To avoid this problem, it is safe to follow the simple rule: do not choose a word that appears in the body of the text as a closing identifier.

[!WARNING] Prior to PHP 7.3.0, it is very important to note that the line with the closing identifier must contain no other characters, except a semicolon (;). That means especially that the identifier may not be indented, and there may not be any spaces or tabs before or after the semicolon. It's also important to realize that the first character before the closing identifier must be a newline as defined by the local operating system. This is \n on UNIX systems, including macOS. The closing delimiter must also be followed by a newline.

If this rule is broken and the closing identifier is not "clean", it will not be considered a closing identifier, and PHP will continue looking for one. If a proper closing identifier is not found before the end of the current file, a parse error will result at the last line.

Invalid example, prior to PHP 7.3.0

      

<?php
class foo {
    public $bar = <<<EOT
bar
    EOT;
}
// Identifier must not be indented
?>

     

Valid example, even prior to PHP 7.3.0

      

<?php
class foo {
    public $bar = <<<EOT
bar
EOT;
}
?>

     

Heredocs containing variables can not be used for initializing class properties.

Heredoc text behaves just like a double-quoted string, without the double quotes. This means that quotes in a heredoc do not need to be escaped, but the escape codes listed above can still be used. Variables are expanded, but the same care must be taken when expressing complex variables inside a heredoc as with strings.

Heredoc string quoting example

<?php
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;

/* More complex example, with variables. */
class foo
{
    var $foo;
    var $bar;

    function __construct()
    {
        $this->foo = 'Foo';
        $this->bar = array('Bar1', 'Bar2', 'Bar3');
    }
}

$foo = new foo();
$name = 'MyName';

echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>

    

ENTITY

My name is "MyName". I am printing some Foo.
Now, I am printing some Bar2.
This should print a capital 'A': A

It is also possible to use the Heredoc syntax to pass data to function arguments:

Heredoc in arguments example

<?php
var_dump(array(<<<EOD
foobar!
EOD
));
?>

    

It's possible to initialize static variables and class properties/constants using the Heredoc syntax:

Using Heredoc to initialize static values

<?php
// Static variables
function foo()
{
    static $bar = <<<LABEL
Nothing in here...
LABEL;
}

// Class properties/constants
class foo
{
    const BAR = <<<FOOBAR
Constant example
FOOBAR;

    public $baz = <<<FOOBAR
Property example
FOOBAR;
}
?>

    

The opening Heredoc identifier may optionally be enclosed in double quotes:

Using double quotes in Heredoc

<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>

    

Nowdoc

Nowdocs are to single-quoted strings what heredocs are to double-quoted strings. A nowdoc is specified similarly to a heredoc, but no string interpolation is done inside a nowdoc. The construct is ideal for embedding PHP code or other large blocks of text without the need for escaping. It shares some features in common with the SGML ENTITY![CDATA[ ]]ENTITY construct, in that it declares a block of text which is not for parsing.

A nowdoc is identified with the same ENTITYENTITYENTITY sequence used for heredocs, but the identifier which follows is enclosed in single quotes, e.g. ENTITYENTITYENTITY'EOT'. All the rules for heredoc identifiers also apply to nowdoc identifiers, especially those regarding the appearance of the closing identifier.

Nowdoc string quoting example

<?php
echo <<<'EOD'
Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.
EOD;

    

ENTITY

Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.

Nowdoc string quoting example with variables

<?php
class foo
{
    public $foo;
    public $bar;

    function __construct()
    {
        $this->foo = 'Foo';
        $this->bar = array('Bar1', 'Bar2', 'Bar3');
    }
}

$foo = new foo();
$name = 'MyName';

echo <<<'EOT'
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41
EOT;
?>

    

ENTITY

My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41

Static data example

<?php
class foo {
    public $bar = <<<'EOT'
bar
EOT;
}
?>

    

String interpolation

When a string is specified in double quotes or with heredoc, variables can be substituted within it.

There are two types of syntax: a basic one and an advanced one. The basic syntax is the most common and convenient. It provides a way to embed a variable, an array value, or an object property in a string with a minimum of effort.

Basic syntax

If a dollar sign ($) is encountered, the characters that follow it which can be used in a variable name will be interpreted as such and substituted.

String Interpolation

<?php
$juice = "apple";

echo "He drank some $juice juice." . PHP_EOL;

?>

     

ENTITY

He drank some apple juice.

Formally, the structure for the basic variable substitution syntax is as follows:

string-variable::
     variable-name   (offset-or-property)?
   | ${   expression   }

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

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

property-in-string::
     ->  name

variable-name::
     $   name

name::
     [a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*

[!WARNING] The ${ expression } syntax is deprecated as of PHP 8.2.0, as it can be interpreted as variable variables:

<?php
const foo = 'bar';
$foo = 'foo';
$bar = 'bar';
var_dump("${foo}");
var_dump("${(foo)}");
?>

       

ENTITY

Deprecated: Using ${var} in strings is deprecated, use {$var} instead in file on line 6

Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead in file on line 9
string(3) "foo"
string(3) "bar"

ENTITY

string(3) "foo"
string(3) "bar"

The advanced string interpolation syntax should be used instead.

[!NOTE] If it is not possible to form a valid name the dollar sign remains verbatim in the string:

<?php
echo "No interpolation $  has happened\n";
echo "No interpolation $\n has happened\n";
echo "No interpolation $2 has happened\n";
?>

      

ENTITY

No interpolation $  has happened
No interpolation $
 has happened
No interpolation $2 has happened

Interpolating the value of the first dimension of an array or property

<?php
$juices = array("apple", "orange", "string_key" => "purple");

echo "He drank some $juices[0] juice.";
echo PHP_EOL;
echo "He drank some $juices[1] juice.";
echo PHP_EOL;
echo "He drank some $juices[string_key] juice.";
echo PHP_EOL;

class A {
    public $s = "string";
}

$o = new A();

echo "Object value: $o->s.";
?>

     

ENTITY

He drank some apple juice.
He drank some orange juice.
He drank some purple juice.
Object value: string.

[!NOTE] The array key must be unquoted, and it is therefore not possible to refer to a constant as a key with the basic syntax. Use the advanced syntax instead.

As of PHP 7.1.0, negative numeric indices are supported too.

Negative numeric indices

<?php
$string = 'string';
echo "The character at index -2 is $string[-2].", PHP_EOL;
$string[-3] = 'o';
echo "Changing the character at index -3 to o gives $string.", PHP_EOL;
?>

     

ENTITY

The character at index -2 is n.
Changing the character at index -3 to o gives strong.

For anything more complex, the advanced syntax must be used.

Advanced (curly) syntax

The advanced syntax permits the interpolation of variables with arbitrary accessors.

Any scalar variable, array element or object property (static or not) with a string representation can be included via this syntax. The expression is written the same way as it would appear outside the string, and then wrapped in { and }. Since { can not be escaped, this syntax will only be recognised when the $ immediately follows the {. Use {\$ to get a literal {$. Some examples to make it clear:

Curly Syntax

<?php
const DATA_KEY = 'const-key';
$great = 'fantastic';
$arr = [
    '1',
    '2',
    '3',
    [41, 42, 43],
    'key' => 'Indexed value',
    'const-key' => 'Key with minus sign',
    'foo' => ['foo1', 'foo2', 'foo3']
];

// Won't work, outputs: This is { fantastic}
echo "This is { $great}" . PHP_EOL;

// Works, outputs: This is fantastic
echo "This is {$great}" . PHP_EOL;

// To show curly braces in the output:
echo "This is {{$great}}" . PHP_EOL;

class Square {
    public $width;

    public function __construct(int $width) { $this->width = $width; }
}

$square = new Square(5);

// Works
echo "This square is {$square->width}00 centimeters wide." . PHP_EOL;


// Works, quoted keys only work using the curly brace syntax
echo "This works: {$arr['key']}" . PHP_EOL;


// Works
echo "This works: {$arr[3][2]}" . PHP_EOL;

echo "This works: {$arr[DATA_KEY]}" . PHP_EOL;

// When using multidimensional arrays, always use braces around arrays
// when inside of strings
echo "This works: {$arr['foo'][2]}" . PHP_EOL;

echo "This works: {$obj->values[3]->name}" . PHP_EOL;

echo "This works: {$obj->$staticProp}" . PHP_EOL;

// Won't work, outputs: C:\directory\{fantastic}.txt
echo "C:\directory\{$great}.txt" . PHP_EOL;

// Works, outputs: C:\directory\fantastic.txt
echo "C:\\directory\\{$great}.txt" . PHP_EOL;
?>

     

[!NOTE] As this syntax allows arbitrary expressions, it is possible to use variable variables within the advanced syntax.

String access and modification by character

Characters within strings may be accessed and modified by specifying the zero-based offset of the desired character after the string using square array brackets, as in $str[42]. Think of a string as an array of characters for this purpose. The functions substr and substr_replace can be used when you want to extract or replace more than 1 character.

[!NOTE] As of PHP 7.1.0, negative string offsets are also supported. These specify the offset from the end of the string. Formerly, negative offsets emitted E_NOTICE for reading (yielding an empty string) and E_WARNING for writing (leaving the string untouched).

[!NOTE] Prior to PHP 8.0.0, strings could also be accessed using braces, as in $str{42}, for the same purpose. This curly brace syntax was deprecated as of PHP 7.4.0 and no longer supported as of PHP 8.0.0.

[!WARNING] Writing to an out-of-range offset pads the string with spaces. Non-integer types are converted to an integer. An illegal offset type emits E_WARNING. Only the first character of an assigned string is used. As of PHP 7.1.0, assigning an empty string throws a fatal error. Formerly, it assigned a NULL byte.

[!WARNING] Internally, PHP strings are byte arrays. As a result, accessing or modifying a string using array brackets is not multi-byte safe, and should only be done with strings that are in a single-byte encoding such as ISO-8859-1.

[!NOTE] As of PHP 7.1.0, applying the empty index operator on an empty string throws a fatal error. Formerly, the empty string was silently converted to an array.

Some string examples

<?php
// Get the first character of a string
$str = 'This is a test.';
$first = $str[0];
var_dump($first);

// Get the third character of a string
$third = $str[2];
var_dump($third);

// Get the last character of a string.
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
var_dump($last);

// Modify the last character of a string
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
var_dump($str);
?>

    

String offsets must be either integers or integer-like strings. As of PHP 8.0.0, any other string throws a TypeError, except for a string starting with an integer followed by other characters, which emits E_WARNING and is interpreted as that leading integer. Prior to PHP 8.0.0, no TypeError was thrown: an illegal offset emitted E_WARNING instead.

Example of Illegal String Offsets

<?php
$str = 'abc';

$keys = [ '1', '1.0', 'x', '1x' ];

foreach ($keys as $keyToTry) {
    var_dump(isset($str[$keyToTry]));

    try {
        var_dump($str[$keyToTry]);
    } catch (TypeError $e) {
        echo $e->getMessage(), PHP_EOL;
    }

    echo PHP_EOL;
}
?>

    

ENTITY

bool(true)
string(1) "b"

bool(false)
Cannot access offset of type string on string

bool(false)
Cannot access offset of type string on string

bool(false)

Warning: Illegal string offset "1x" in example.php on line 10
string(1) "b"

ENTITY

bool(true)
string(1) "b"

bool(false)

Warning: Illegal string offset '1.0' in example.php on line 10
string(1) "b"

bool(false)

Warning: Illegal string offset 'x' in example.php on line 10
string(1) "a"

bool(false)

Notice: A non well formed numeric value encountered in example.php on line 10
string(1) "b"

[!NOTE] Accessing variables of other types (not including arrays or objects implementing the appropriate interfaces) using [] or {} silently returns ENTITY.

[!NOTE] Characters within string literals can be accessed using [] or {}.

[!NOTE] Accessing characters within string literals using the {} syntax has been deprecated in PHP 7.4. This has been removed in PHP 8.0.

Useful functions and operators

Strings may be concatenated using the '.' (dot) operator. Note that the '+' (addition) operator will not work for this. See String operators for more information.

There are a number of useful functions for string manipulation.

See the string functions section for general functions, and the Perl-compatible regular expression functions for advanced find ENTITY replace functionality.

There are also functions for URL strings, and functions to encrypt/decrypt strings (Sodium and Hash).

Finally, see also the character type functions.

Converting to string

A value can be converted to a string using the (string) cast or the strval function. String conversion is automatically done in the scope of an expression where a string is needed. This happens when using the echo or print functions, or when a variable is compared to a string. The sections on Types and Type Juggling will make the following clearer. See also the settype function.

A bool ENTITY value is converted to the string "1". bool ENTITY is converted to "" (the empty string). This allows conversion back and forth between bool and string values.

An int or float is converted to a string representing the number textually (including the exponent part for floats). Floating-point numbers can be converted using exponential notation (4.1E+6).

[!NOTE] As of PHP 8.0.0, the decimal point character is always a period ("."). Prior to PHP 8.0.0, the decimal point character is defined in the script's locale (category LC_NUMERIC). See the setlocale function.

Arrays are always converted to the string "Array"; because of this, echo and print can not by themselves show the contents of an array. To view a single element, use a construction such as echo $arr['foo']. See below for tips on viewing the entire contents.

In order to convert objects to string, the magic method __toString must be used.

Resources are always converted to strings with the structure "Resource id #1", where 1 is the resource number assigned to the resource by PHP at runtime. While the exact structure of this string should not be relied on and is subject to change, it will always be unique for a given resource within the lifetime of a script being executed (ie a Web request or CLI process) and won't be reused. To get a resource's type, use the get_resource_type function.

ENTITY is always converted to an empty string.

As stated above, directly converting an array, object, or resource to a string does not provide any useful information about the value beyond its type. See the functions print_r and var_dump for more effective means of inspecting the contents of these types.

Most PHP values can also be converted to strings for permanent storage. This method is called serialization, and is performed by the serialize function.

Details of the String Type

The string in PHP is implemented as an array of bytes and an integer indicating the length of the buffer. It has no information about how those bytes translate to characters, leaving that task to the programmer. There are no limitations on the values the string can be composed of; in particular, bytes with value 0 (“NUL bytes”) are allowed anywhere in the string. However, a few functions, said in this manual not to be “binary safe”, may hand off the strings to libraries that ignore data after a NUL byte.

This nature of the string type explains why there is no separate “byte” type in PHP – strings take this role. Functions that return no textual data – for instance, arbitrary data read from a network socket – will still return strings.

Given that PHP does not dictate a specific encoding for strings, one might wonder how string literals are encoded. For instance, is the string "á" equivalent to "\xE1" (ISO-8859-1), "\xC3\xA1" (UTF-8, C form), "\x61\xCC\x81" (UTF-8, D form) or any other possible representation? The answer is that the string will be encoded in whatever fashion it is encoded in the script file. Thus, if the script is written in ISO-8859-1, the string will be encoded in ISO-8859-1 and so on. However, this does not apply if Zend Multibyte is enabled; in that case, the script may be written in an arbitrary encoding (which is explicitly declared or is detected) and then converted to a certain internal encoding, which is then the encoding that will be used for the string literals. Note that there are some constraints on the encoding of the script (or on the internal encoding, should Zend Multibyte be enabled) – this almost always means that this encoding should be a compatible superset of ASCII, such as UTF-8 or ISO-8859-1. Note, however, that state-dependent encodings where the same byte values can be used in initial and non-initial shift states may be problematic.

Of course, in order to be useful, functions that operate on text may have to make some assumptions about how the string is encoded. Unfortunately, there is much variation on this matter throughout PHP’s functions:

Ultimately, this means writing correct programs using Unicode depends on carefully avoiding functions that will not work and that most likely will corrupt the data and using instead the functions that do behave correctly, generally from the intl and mbstring extensions. However, using functions that can handle Unicode encodings is just the beginning. No matter the functions the language provides, it is essential to know the Unicode specification. For instance, a program that assumes there is only uppercase and lowercase is making a wrong assumption.

Type Juggling

PHP does not require explicit type definition in variable declaration. In this case, the type of a variable is determined by the value it stores. That is to say, if a string is assigned to variable $var, then $var is of type string. If afterwards an int value is assigned to $var, it will be of type int.

PHP may attempt to convert the type of a value to another automatically in certain contexts. The different contexts which exist are:

[!NOTE] When a value needs to be interpreted as a different type, the value itself does not change types.

To force a variable to be evaluated as a certain type, see the section on Type casting. To change the type of a variable, see the settype function.

Numeric contexts

This is the context when using an arithmetical operator.

In this context, if either operand is a float (or not interpretable as an int), both operands are interpreted as floats, and the result will be a float. Otherwise, the operands will be interpreted as ints, and the result will also be an int. As of PHP 8.0.0, if one of the operands cannot be interpreted, a TypeError is thrown.

String contexts

This is the context when using echo, print, string interpolation, or the string concatenation operator.

In this context, the value will be interpreted as string. If the value cannot be interpreted, a TypeError is thrown. Prior to PHP 7.4.0, an E_RECOVERABLE_ERROR was raised.

Logical contexts

This is the context when using conditional statements, the ternary operator, or a logical operator.

In this context, the value will be interpreted as bool.

Integral and string contexts

This is the context when using bitwise operators.

In this context, if all operands are of type string, the result will also be a string. Otherwise, the operands will be interpreted as ints, and the result will also be an int. As of PHP 8.0.0, if one of the operands cannot be interpreted, a TypeError is thrown.

Comparative contexts

This is the context when using a comparison operator.

The type conversions which occur in this context are explained in the Comparison with Various Types table.

Function contexts

This is the context when a value is passed to a typed parameter, property, or returned from a function which declares a return type.

In this context, the value must be a value of the type. Two exceptions exist. The first one is: if the value is of type int and the declared type is float, then the integer is converted to a floating point number. The second one is: if the declared type is a scalar type, the value is convertible to a scalar type, and the coercive typing mode is active (the default), the value may be converted to an accepted scalar value. See below for a description of this behaviour.

[!WARNING] Internal functions automatically coerce ENTITY to scalar types. This behaviour is DEPRECATED as of PHP 8.1.0.

Coercive typing with simple type declarations

Coercive typing with union types

When strict_types is not enabled, scalar type declarations are subject to limited implicit type coercions. If the exact type of the value is not part of the union, then the target type is chosen in the following order of preference:

  1. int

  2. float

  3. string

  4. bool

If the type exists in the union and the value can be coerced to the type under PHP's existing type-checking semantics, then the type is chosen. Otherwise, the next type is tried.

[!CAUTION] As an exception, if the value is a string and both int and float are part of the union, the preferred type is determined by the existing numeric string semantics. For example, for "42" int is chosen, while for "42.0" float is chosen.

[!NOTE] Types that are not part of the above preference list are not eligible targets for implicit coercion. In particular, no implicit coercions to the null, false, and true types occur.

Example of types being coerced into a type part of the union

<?php
// int|string
42    --> 42          // exact type
"42"  --> "42"        // exact type
new ObjectWithToString --> "Result of __toString()"
                      // object never compatible with int, fall back to string
42.0  --> 42          // float compatible with int
42.1  --> 42          // float compatible with int
1e100 --> "1.0E+100"  // float too large for int type, fall back to string
INF   --> "INF"       // float too large for int type, fall back to string
true  --> 1           // bool compatible with int
[]    --> TypeError   // array not compatible with int or string

// int|float|bool
"45"    --> 45        // int numeric string
"45.0"  --> 45.0      // float numeric string

"45X"   --> true      // not numeric string, fall back to bool
""      --> false     // not numeric string, fall back to bool
"X"     --> true      // not numeric string, fall back to bool
[]      --> TypeError // array not compatible with int, float or bool
?>

    

Type Casting

Type casting converts the value to a chosen type by writing the type within parentheses before the value to convert.

Type Casting

<?php
$foo = 10;          // $foo is an integer
$bar = (bool) $foo; // $bar is a boolean

var_dump($bar);
?>

   

The casts allowed are:

(int)

- cast to

int

(bool)

- cast to

bool

(float)

- cast to

float

(string)

- cast to

string

(array)

- cast to

array

(object)

- cast to

object

(unset)

- cast to

NULL

The (void) cast is also available as of PHP 8.5.0, but it is not a value conversion. It is used as a statement to explicitly discard the result of an expression.

[!WARNING] (integer) is an alias of the (int) cast. (boolean) is an alias of the (bool) cast. (binary) is an alias of the (string) cast. (double) and (real) are aliases of the (float) cast. These casts do not use the canonical type name and are deprecated as of PHP 8.5.0.

[!WARNING] The (real) cast alias has been deprecated as of PHP 7.4.0 and removed as of PHP 8.0.0.

[!WARNING] The (unset) cast has been deprecated as of PHP 7.2.0. Note that the (unset) cast is the same as assigning the value NULL to the variable or call. The (unset) cast is removed as of PHP 8.0.0.

[!CAUTION] The (binary) cast and b prefix exist for forward support. Currently (binary) and (string) are identical, however this may change and should not be relied upon.

[!NOTE] Whitespaces are ignored within the parentheses of a cast. Therefore, the following two casts are equivalent:

<?php
$foo = (int) $bar;
$foo = ( int ) $bar;
?>

     

Casting literal strings and variables to binary strings:

<?php
$binary = (binary) $string;
$binary = b"binary string";
?>

   

Instead of casting a variable to a string, it is also possible to enclose the variable in double quotes.

Different Casting Mechanisms

<?php
$foo = 10;            // $foo is an integer
$str = "$foo";        // $str is a string
$fst = (string) $foo; // $fst is also a string

// This prints out that "they are the same"
if ($fst === $str) {
    echo "they are the same", PHP_EOL;
}
?>

   

It may not be obvious exactly what will happen when casting between certain types. For more information, see these sections: Converting to boolean, Converting to integer, Converting to float, Converting to string, Converting to array, Converting to object, Converting to resource, Converting to NULL, Discarding a value with (void), The type comparison tables

[!NOTE] Because PHP supports indexing into strings via offsets using the same syntax as array indexing, the following example holds true for all PHP versions:

Using Array Offset with a String

<?php
$a    = 'car'; // $a is a string
$a[0] = 'b';   // $a is still a string
echo $a;       // bar
?>

    

See the section titled String access by character for more information.

Type System

PHP uses a nominal type system with a strong behavioral subtyping relation. The subtyping relation is checked at compile time whereas the verification of types is dynamically checked at run time.

PHP's type system supports various atomic types that can be composed together to create more complex types. Some of these types can be written as type declarations.

Atomic types

Some atomic types are built-in types which are tightly integrated with the language and cannot be reproduced with user-defined types.

The list of base types is:

Scalar types

A value is considered scalar if it is of type int, float, string or bool.

User-defined types

It is possible to define custom types with interfaces, classes and enumerations. These are considered as user-defined types, or class-types. For example, a class called Elephant can be defined, then objects of type Elephant can be instantiated, and a function can request a parameter of type Elephant.

Composite types

It is possible to combine multiple atomic types into composite types. PHP allows types to be combined in the following ways:

Intersection types

An intersection type accepts values which satisfy multiple class-type declarations, rather than a single one. Individual types which form the intersection type are joined by the ENTITY symbol. Therefore, an intersection type comprised of the types T, U, and V will be written as TENTITYUENTITYV.

Union types

A union type accepts values of multiple different types, rather than a single one. Individual types which form the union type are joined by the | symbol. Therefore, a union type comprised of the types T, U, and V will be written as T|U|V. If one of the types is an intersection type, it needs to be bracketed with parentheses for it to be written in DNF: T|(XENTITYY).

Type aliases

PHP supports two type aliases: mixed and iterable which correspond to the union type of object|resource|array|string|float|int|bool|null and Traversable|array respectively.

[!NOTE] PHP does not support user-defined type aliases.

Void

void is a return-only type declaration indicating the function does not return a value, but the function may still terminate. Therefore, it cannot be part of a union type declaration. Available as of PHP 7.1.0.

A return statement with an expression in a void function is a compile-time error, even if the return would not be reached during execution. This includes return null;; use a bare return; to exit the function early. The null mentioned below is only the implicit value of the call.

[!NOTE] Even if a function has a return type of void, it will still return a value. This value is always ENTITY.

Discarding a value with (void)

The (void) syntax may be used to explicitly discard the result of an expression. This is useful to indicate that ignoring a return value is intentional, especially when calling a function or method marked with the NoDiscard attribute.

Unlike other casts, (void) does not convert the value to another type and does not produce a value. It is a statement and cannot be used as part of an expression.

Discarding a return value

    
<?php
#[\NoDiscard]
function process(): bool {
    return true;
}

(void) process(); // Explicitly discard the return value
?>

   

Variables

Basics

Variables in PHP are represented by a dollar sign followed by the name of the variable. The variable name is case-sensitive.

A valid variable name starts with a letter (A-Z, a-z, or the bytes from 128 through 255) or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$

[!NOTE] Variable names are compared as bytes, not as characters. PHP does not interpret or validate the encoding of the bytes from 128 through 255, and two names refer to the same variable only when their bytes are identical.

One consequence is that names written in UTF-8 work, because every byte of a UTF-8 multi-byte sequence falls inside the accepted range. The same holds for any encoding whose non-ASCII bytes all fall in that range, and for byte sequences that are not valid text in any encoding. Encodings that use bytes below 128 within a multi-byte sequence, such as Shift-JIS or UTF-16, do not.

Another is that two names which display identically may be distinct. ä encoded as U+00E4 and as a followed by the combining diaeresis U+0308 are different variables, as are a name with and without a trailing U+00A0 NO-BREAK SPACE.

[!NOTE] $this is a special variable that can't be assigned. Prior to PHP 7.1.0, indirect assignment (e.g. by using variable variables) was possible.

ENTITY

Valid variable names

<?php
$var = 'Bob';
$Var = 'Joe';
echo "$var, $Var";      // outputs "Bob, Joe"

$_4site = 'not yet';    // valid; starts with an underscore
$täyte = 'mansikka';    // valid; 'ä' is (Extended) ASCII 228.

    

Invalid variable names

<?php
$4site = 'not yet';     // invalid; starts with a number

    

PHP accepts a sequence of any bytes as a variable name. Variable names that do not follow the above-mentioned naming rules can only be accessed dynamically at runtime. See variable variables for information on how to access them.

Accessing obscure variable names

<?php
${'invalid-name'} = 'bar';
$name = 'invalid-name';
echo ${'invalid-name'}, " ", $$name;

    

ENTITY

bar bar

By default, variables are always assigned by value. That is to say, when an expression is assigned to a variable, the entire value of the original expression is copied into the destination variable. This means, for instance, that after assigning one variable's value to another, changing one of those variables will have no effect on the other. For more information on this kind of assignment, see the chapter on Expressions.

PHP also offers another way to assign values to variables: assign by reference. This means that the new variable simply references (in other words, "becomes an alias for" or "points to") the original variable. Changes to the new variable affect the original, and vice versa.

To assign by reference, simply prepend an ampersand (ENTITY) to the beginning of the variable which is being assigned (the source variable). For instance, the following code snippet outputs 'My name is Bob' twice:

<?php
$foo = 'Bob';              // Assign the value 'Bob' to $foo
$bar = &$foo;              // Reference $foo via $bar.
$bar = "My name is $bar";  // Alter $bar...
echo $bar . PHP_EOL;
echo $foo . PHP_EOL;       // $foo is altered too.

     

One important thing to note is that only variables may be assigned by reference.

<?php
$original = 25;
$ref1 = &$original;        // This is a valid assignment.
$ref2 = &(24 * 7);         // Invalid; references an unnamed expression.

     
<?php
// Note the lack of & indicating a returned reference in the function declaration.
// i.e. the function does not return a reference, so the result cannot be assigned by reference
function test()
{
   $original = 25;
   return $original;
}

// Note: A notice is issued, but the non-reference value is assigned
$result1 = &test();        // Invalid because test() doesn't return a variable by reference.
var_dump($result1);

// This function is defined as returning a reference, but does not return a variable
function &test2()
{
    return 26;             // Invalid because the returned value isn't a variable reference.
}

// Note: The non-reference value is assigned
$result2 = &test2();
var_dump($result2);

     

It is not necessary to declare variables in PHP, however, it is a very good practice. Accessing an undefined variable will result in an E_WARNING (prior to PHP 8.0.0, E_NOTICE). An undefined variable has a default value of ENTITY. The isset language construct can be used to detect if a variable has already been initialized.

Default value of an uninitialized variable

<?php
// Unset AND unreferenced (no use context) variable.
var_dump($unset_var);

     

ENTITY

Warning: Undefined variable $unset_var in ...
NULL

PHP allows array autovivification (automatic creation of new arrays) from an undefined variable. Appending an element to an undefined variable will create a new array and will not generate a warning.

Autovivification of an array from an undefined variable

<?php
$unset_array[] = 'value'; // Does not generate a warning.
var_dump($unset_array);

    

[!WARNING] Relying on the default value of an uninitialized variable is problematic when including one file in another which uses the same variable name.

A variable can be destroyed by using the unset language construct.

For information on variable-related functions, see the Variable Functions Reference.

Predefined Variables

PHP provides a number of predefined variables. PHP also provides an additional set of predefined arrays containing variables from the web server (if applicable), the environment, and user input. These arrays are automatically available in every scope. For this reason, they are often known as "superglobals". (There is no mechanism in PHP for user-defined superglobals.) Refer to the list of superglobals for details.

[!NOTE] Superglobals cannot be used as variable variables inside functions or class methods.

If certain variables in variables_order are not set, their appropriate PHP predefined arrays are also left empty.

Variable scope

The scope of a variable is the context within which it is defined. PHP has a function scope and a global scope. Any variable defined outside a function is limited to the global scope. When a file is included, the code it contains inherits the variable scope of the line on which the include occurs.

Example of global variable scope

<?php
$a = 1;
include 'b.inc'; // Variable $a will be available within b.inc

    

Any variable created inside a named function or an anonymous function is limited to the scope of the function body. However, arrow functions bind variables from the parent scope to make them available inside the body. If a file include occurs inside a function within the calling file, the variables contained in the called file will be available as if they had been defined inside the calling function.

Example of local variable scope

 

<?php
$a = 1; // global scope

function test()
{ 
    var_dump($a); // Variable $a is undefined as it refers to a local version of $a
}

test();

    

The example above will generate an undefined variable E_WARNING (or an E_NOTICE prior to PHP 8.0.0). This is because the echo statement refers to a local version of the $a variable, and it has not been assigned a value within this scope. Note that this is a little bit different from the C language in that global variables in C are automatically available to functions unless specifically overridden by a local definition. This can cause some problems in that people may inadvertently change a global variable. In PHP global variables must be declared global inside a function if they are going to be used in that function.

The global keyword

The global keyword is used to bind a variable from a global scope into a local scope. The keyword can be used with a list of variables or a single variable. A local variable will be created referencing the global variable of the same name. If the global variable does not exist, the variable will be created in global scope and assigned ENTITY.

Using global

<?php
$a = 1;
$b = 2;

function Sum()
{
    global $a, $b;

    $b = $a + $b;
} 

Sum();
echo $b;

      

ENTITY

3

By declaring $a and $b global within the function, all references to either variable will refer to the global version. There is no limit to the number of global variables that can be manipulated by a function.

A second way to access variables from the global scope is to use the special PHP-defined $GLOBALS array. The previous example can be rewritten as:

Using $GLOBALS instead of global

<?php
$a = 1;
$b = 2;

function Sum()
{
    $GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
} 

Sum();
echo $b;

     

The $GLOBALS array is an associative array with the name of the global variable being the key and the contents of that variable being the value of the array element. Notice how $GLOBALS exists in any scope, this is because $GLOBALS is a superglobal. Here's an example demonstrating the power of superglobals:

Example demonstrating superglobals and scope

<?php
function test_superglobal()
{
    echo $_POST['name'];
}

     

[!NOTE] Using global keyword outside a function is not an error. It can be used if the file is included from inside a function.

Using static variables

Another important feature of variable scoping is the static variable. A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope. Consider the following example:

Example demonstrating need for static variables

<?php
function test()
{
    $a = 0;
    echo $a . PHP_EOL;
    $a++;
}

test();
test();
test();

     

This function is quite useless since every time it is called it sets $a to 0 and prints 0. The $a++ which increments the variable serves no purpose since as soon as the function exits the $a variable disappears. To make a useful counting function which will not lose track of the current count, the $a variable is declared static:

Example use of static variables

<?php
function test()
{
    static $a = 0;
    echo $a . PHP_EOL;
    $a++;
}

test();
test();
test();

     

Now, $a is initialized only in first call of function and every time the test() function is called it will print the value of $a and increment it.

Static variables also provide one way to deal with recursive functions. The following simple function recursively counts to 10, using the static variable $count to know when to stop:

Static variables with recursive functions

<?php
function test()
{
    static $count = 0;

    $count++;
    echo $count . PHP_EOL;
    if ($count < 10) {
        test();
    }
    // Undo the increment, so $count is back to 0 once test() has finished
    // and a later call to test() counts from 1 again
    $count--;
}

test();

     

ENTITY

1
2
3
4
5
6
7
8
9
10

Prior to PHP 8.3.0, static variables could only be initialized using a constant expression. As of PHP 8.3.0, dynamic expressions (e.g. function calls) are also allowed:

Declaring static variables

<?php
function foo(){
    static $int = 0;          // correct 
    static $int = 1+2;        // correct
    static $int = sqrt(121);  // correct as of PHP 8.3.0

    $int++;
    echo $int;
}

     

Static variables inside anonymous functions persist only within that specific function instance. If the anonymous function is recreated on each call, the static variable will be reinitialized.

Static variables in anonymous functions

<?php
function exampleFunction($input) {
    $result = (static function () use ($input) {
        static $counter = 0;
        $counter++;
        return "Input: $input, Counter: $counter\n";
    });

    return $result();
}

// Calls to exampleFunction will recreate the anonymous function, so the static
// variable does not retain its value.
echo exampleFunction('A'); // Outputs: Input: A, Counter: 1
echo exampleFunction('B'); // Outputs: Input: B, Counter: 1

    

As of PHP 8.1.0, when a method using static variables is inherited (but not overridden), the inherited method will now share static variables with the parent method. This means that static variables in methods now behave the same way as static properties.

As of PHP 8.3.0, static variables can be initialized with arbitrary expressions. This means that method calls, for example, can be used to initialize static variables.

Usage of static Variables in Inherited Methods

<?php
class Foo {
    public static function counter() {
        static $counter = 0;
        $counter++;
        return $counter;
    }
}
class Bar extends Foo {}
var_dump(Foo::counter()); // int(1)
var_dump(Foo::counter()); // int(2)
var_dump(Bar::counter()); // int(3), prior to PHP 8.1.0 int(1)
var_dump(Bar::counter()); // int(4), prior to PHP 8.1.0 int(2)

    

References with global and static variables

PHP implements the static and global modifier for variables in terms of references. For example, a true global variable imported inside a function scope with the global statement actually creates a reference to the global variable. This can lead to unexpected behaviour which the following example addresses:

<?php
function test_global_ref() {
    global $obj;
    $new = new stdClass;
    $obj = &$new;
}

function test_global_noref() {
    global $obj;
    $new = new stdClass;
    $obj = $new;
}

test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);

    

ENTITY

NULL
object(stdClass)#1 (0) {
}

A similar behaviour applies to the static statement. References are not stored statically:

<?php
function &get_instance_ref() {
    static $obj;

    echo 'Static object: ';
    var_dump($obj);
    if (!isset($obj)) {
        $new = new stdClass;
        // Assign a reference to the static variable
        $obj = &$new;
    }
    if (!isset($obj->property)) {
        $obj->property = 1;
    } else {
        $obj->property++;
    }
    return $obj;
}

function &get_instance_noref() {
    static $obj;

    echo 'Static object: ';
    var_dump($obj);
    if (!isset($obj)) {
        $new = new stdClass;
        // Assign the object to the static variable
        $obj = $new;
    }
    if (!isset($obj->property)) {
        $obj->property = 1;
    } else {
        $obj->property++;
    }
    return $obj;
}

$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo "\n";
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();

    

ENTITY

Static object: NULL
Static object: NULL

Static object: NULL
Static object: object(stdClass)#3 (1) {
  ["property"]=>
  int(1)
}

This example demonstrates that when assigning a reference to a static variable, it is not remembered when the ENTITYget_instance_ref() function is called a second time.

Variable variables

Sometimes it is convenient to be able to have variable variable names. That is, a variable name which can be set and used dynamically. A normal variable is set with a statement such as:

<?php
$a = 'hello';
var_dump($a);

    

A variable variable takes the value of a variable and treats that as the name of a variable. In the above example, hello, can be used as the name of a variable by using two dollar signs. i.e.

<?php
$a = 'hello';
$$a = 'world';
var_dump($hello);

    

At this point two variables have been defined and stored in the PHP symbol tree: $a with contents "hello" and $hello with contents "world". Therefore, this statement:

<?php
$a = 'hello';
$$a = 'world';
echo "$a {$$a}";

    

produces the exact same output as:

<?php
$a = 'hello';
$$a = 'world';
echo "$a $hello";

    

i.e. they both produce: hello world.

In order to use variable variables with arrays, an ambiguity problem has to be resolved. That is, if the parser sees $$a[1] then it needs to know if $a[1] was meant to be used as a variable, or if $$a was wanted as the variable and then the [1] index from that variable. The syntax for resolving this ambiguity is: ${$a[1]} for the first case and ${$a}[1] for the second.

Class properties may also be accessed using variable property names. The variable property name will be resolved within the scope from which the call is made. For instance, if there is an expression such as $foo->$bar, then the local scope will be examined for $bar and its value will be used as the name of the property of $foo. This is also true if $bar is an array access.

Curly braces may also be used to clearly delimit the property name. They are most useful when accessing values within a property that contains an array, when the property name is made of multiple parts, or when the property name contains characters that are not otherwise valid (e.g. from json_decode or SimpleXML).

Variable property example

<?php
class Foo {
    public $bar = 'I am bar.';
    public $arr = ['I am A.', 'I am B.', 'I am C.'];
    public $r   = 'I am r.';
}

$foo = new Foo();
$bar = 'bar';
$baz = ['foo', 'bar', 'baz', 'quux'];
echo $foo->$bar . "\n";
echo $foo->{$baz[1]} . "\n";

$start = 'b';
$end   = 'ar';
echo $foo->{$start . $end} . "\n";

$arr = 'arr';
echo $foo->{$arr[1]} . "\n";
echo $foo->{$arr}[1] . "\n";

     

ENTITY

I am bar.
I am bar.
I am bar.
I am r.
I am B.

[!WARNING] Please note that variable variables cannot be used with PHP's Superglobal arrays within functions or class methods. The variable $this is also a special variable that cannot be referenced dynamically.

Variables From External Sources

HTML Forms (GET and POST)

When a form is submitted to a PHP script, the information from that form is automatically made available to the script. There are few ways to access this information, for example:

A simple HTML form

<form action="foo.php" method="post">
    Name:  <input type="text" name="username" /><br />
    Email: <input type="text" name="email" /><br />
    <input type="submit" name="submit" value="Submit me!" />
</form>

      

There are only two ways to access data from HTML forms. Currently available methods are listed below:

Accessing data from a simple POST HTML form

<?php
echo $_POST['username'];
echo $_REQUEST['username'];

      

Using a GET form is similar except the appropriate GET predefined variable can be used instead. GET also applies to the QUERY_STRING (the information after the '?' in a URL). So, for example, http://www.example.com/test.php?id=3 contains GET data which is accessible with $_GET['id']. See also $_REQUEST.

[!NOTE] Dots and spaces in variable names are converted to underscores. For example ENTITYinput name="a.b" /ENTITY becomes $_REQUEST["a_b"].

PHP also understands arrays in the context of form variables (see the related faq). For example, related variables may be grouped together, or this feature may be used to retrieve values from a multiple select input. For example, let's post a form to itself and upon submission display the data:

More complex form variables

<?php
if ($_POST) {
    echo '<pre>';
    echo htmlspecialchars(print_r($_POST, true));
    echo '</pre>';
}
?>
<form action="" method="post">
    Name:  <input type="text" name="personal[name]" /><br />
    Email: <input type="text" name="personal[email]" /><br />
    Beer: <br />
    <select multiple name="beer[]">
        <option value="warthog">Warthog</option>
        <option value="guinness">Guinness</option>
        <option value="stuttgarter">Stuttgarter Schwabenbräu</option>
    </select><br />
    <input type="submit" value="submit me!" />
</form>

      

[!NOTE] If an external variable name begins with a valid array syntax, trailing characters are silently ignored. For example, ENTITYinput name="foo[bar]baz"ENTITY becomes $_REQUEST['foo']['bar'].

IMAGE SUBMIT variable names

When submitting a form, it is possible to use an image instead of the standard submit button with a tag like:

<input type="image" src="image.gif" name="sub" />

      

When the user clicks somewhere on the image, the accompanying form will be transmitted to the server with two additional variables, sub_x and sub_y. These contain the coordinates of the user click within the image. The experienced may note that the actual variable names sent by the browser contains a period rather than an underscore, but PHP converts the period to an underscore automatically.

HTTP Cookies

PHP transparently supports HTTP cookies as defined by RFC 6265. Cookies are a mechanism for storing data in the remote browser and thus tracking or identifying return users. It is possible to set cookies using the setcookie function. Cookies are part of the HTTP header, so the SetCookie function must be called before any output is sent to the browser. This is the same restriction as for the header function. Cookie data is then available in the appropriate cookie data arrays, such as $_COOKIE as well as in $_REQUEST. See the setcookie manual page for more details and examples.

[!NOTE] As of PHP 7.2.34, 7.3.23 and 7.4.11, respectively, the names of incoming cookies are no longer url-decoded for security reasons.

If multiple values should be assigned to a single cookie variable, they can be assigned as an array. For example:

<?php
setcookie("MyCookie[foo]", 'Testing 1', time()+3600);
setcookie("MyCookie[bar]", 'Testing 2', time()+3600);

     

That will create two separate cookies although MyCookie will now be a single array in the script. If just one cookie should be set with multiple values, consider using serialize or explode on the value first.

A setcookie example

<?php
if (isset($_COOKIE['count'])) {
    $count = $_COOKIE['count'] + 1;
} else {
    $count = 1;
}
setcookie('count', $count, time()+3600);
setcookie("Cart[$count]", $item, time()+3600);

     

Dots in incoming variable names

Typically, PHP does not alter the names of variables when they are passed into a script. However, it should be noted that the dot (period, full stop) is not a valid character in a PHP variable name. For the reason, look at it:

<?php
$varname.ext;  /* invalid variable name */

     

Now, what the parser sees is a variable named $varname, followed by the string concatenation operator, followed by the barestring (i.e. unquoted string which doesn't match any known key or reserved words) 'ext'. Obviously, this doesn't have the intended result.

For this reason, it is important to note that PHP will automatically replace any dots in incoming variable names with underscores.

Determining variable types

Because PHP determines the types of variables and converts them (generally) as needed, it is not always obvious what type a given variable is at any one time. PHP includes several functions which find out what type a variable is, such as: gettype, is_array, is_float, is_int, is_object, and is_string. See also the chapter on Types.

HTTP being a text protocol, most, if not all, content that comes in Superglobal arrays, like $_POST and $_GET will remain as strings. PHP will not try to convert values to a specific type. In the example below, $_GET["var1"] will contain the string "null" and $_GET["var2"], the string "123".

/index.php?var1=null&var2=123

ENTITY

ENTITY ENTITY
7.2.34, 7.3.23, 7.4.11 The names of incoming cookies are no longer url-decoded for security reasons.

wrappers

PHP comes with many built-in wrappers for various URL-style protocols for use with the filesystem functions such as fopen, copy, file_exists and filesize. In addition to these wrappers, it is possible to register custom wrappers using the stream_wrapper_register function.

[!NOTE] The URL syntax used to describe a wrapper only supports the scheme://... syntax. The scheme:/ and scheme: syntaxes are not supported.

ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY ENTITY

audio

ogg://

Audio streams

ENTITY

Files opened for reading via the ogg:// wrapper are treated as compressed audio encoded using the OGG/Vorbis codec. Similarly, files opened for writing or appending via the ogg:// wrapper are written as compressed audio data. stream_get_meta_data, when used on an OGG/Vorbis file opened for reading will return various details about the stream including the vendor tag, any included comments, the number of channels, the sampling rate, and the encoding rate range described by: bitrate_lower, bitrate_upper, bitrate_nominal, and bitrate_window.

ogg:// (PECL)

[!NOTE] In order to use the ogg:// wrapper, the OGG/Vorbis extension available from ENTITY must be installed.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Allows Reading Yes
Allows Writing Yes
Allows Appending Yes
Allows Simultaneous Reading and Writing No
Supports stat No
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

Name Usage Default Mode
pcm_mode PCM encoding to apply while reading, one of: OGGVORBIS_PCM_U8, OGGVORBIS_PCM_S8, OGGVORBIS_PCM_U16_BE, OGGVORBIS_PCM_S16_BE, OGGVORBIS_PCM_U16_LE, and OGGVORBIS_PCM_S16_LE. (8 vs 16 bit, signed or unsigned, big or little endian) OGGVORBIS_PCM_S16_LE Read
rate Sampling rate of input data, expressed in Hz 44100 Write/Append
bitrate When given as an integer, the fixed bitrate at which to encode. (16000 to 131072) When given as a float, the variable bitrate quality to use. (-1.0 to 1.0) 128000 Write/Append
channels The number of audio channels to encode, typically 1 (Mono), or 2 (Stereo). May range as high as 16. 2 Write/Append
comments An array of string values to encode into the track header. Write/Append

Context options {role="stream_wrapper"}

compression

zlib://

bzip2://

zip://

Compression Streams

ENTITY

compress.zlib:// and compress.bzip2://

zlib: works like gzopen, except that the stream can be used with fread and the other filesystem functions. This is deprecated due to ambiguities with filenames containing ':' characters; use compress.zlib:// instead.

compress.zlib:// and compress.bzip2:// are equivalent to gzopen and bzopen respectively, and operate even on systems that do not support fopencookie.

ZIP extension registers zip: wrapper. As of PHP 7.2.0 and libzip 1.2.0+, support for the passwords for encrypted archives were added, allowing passwords to be supplied by stream contexts. Passwords can be set using the 'password' stream context option.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Allows Reading Yes
Allows Writing Yes (except zip://)
Allows Appending Yes (except zip://)
Allows Simultaneous Reading and Writing No
Supports stat No, use the normal file:// wrapper to stat compressed files.
Supports unlink No, use the normal file:// wrapper to unlink compressed files.
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

ENTITY

data

data://

Data (RFC 2397)

ENTITY

The data: (RFC 2397) stream wrapper.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen Yes
Restricted by allow_url_include Yes
Allows Reading Yes
Allows Writing No
Allows Appending No
Allows Simultaneous Reading and Writing No
Supports stat No
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

ENTITY

Print data:// contents

<?php
// prints "I love PHP"
echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo=');
?>

   

Fetch the media type

<?php
$fp   = fopen('data://text/plain;base64,', 'r');
$meta = stream_get_meta_data($fp);

// prints "text/plain"
echo $meta['mediatype'];
?>

   

expect

expect://

Process Interaction Streams

ENTITY

Streams opened via the expect:// wrapper provide access to process's stdin, stdout and stderr via PTY.

[!NOTE] In order to use the expect:// wrapper, the Expect extension available from ENTITY must be installed.

expect:// (PECL)

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Allows Reading Yes
Allows Writing Yes
Allows Appending Yes
Allows Simultaneous Reading and Writing No
Supports stat No
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

file

file://

Accessing local filesystem

ENTITY

file:// is the default wrapper used with PHP and represents the local filesystem. When a relative path is specified (a path which does not begin with /, \, \\, or a Windows drive letter) the path provided will be applied against the current working directory. In many cases this is the directory in which the script resides unless it has been changed. Using the CLI SAPI, this defaults to the directory from which the script was called.

With some functions, such as fopen and file_get_contents, include_path may be optionally searched for relative paths as well.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Allows Reading Yes
Allows Writing Yes
Allows Appending Yes
Allows Simultaneous Reading and Writing Yes
Supports stat Yes
Supports unlink Yes
Supports rename Yes
Supports mkdir Yes
Supports rmdir Yes

Wrapper Summary {role="stream_wrapper"}

ftp

ftp://

ftps://

Accessing FTP(s) URLs

ENTITY

Allows read access to existing files and creation of new files via FTP. If the server does not support passive mode ftp, the connection will fail.

You can open files for either reading or writing, but not both simultaneously. If the remote file already exists on the ftp server and you attempt to open it for writing but have not specified the context option overwrite, the connection will fail. If you need to overwrite existing files over ftp, specify the overwrite option in the context and open the file for writing. Alternatively, you can use the FTP extension.

If you have set the from directive in ENTITY, then this value will be sent as the anonymous FTP password.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen Yes
Allows Reading Yes
Allows Writing Yes (new files/existing files with overwrite)
Allows Appending Yes
Allows Simultaneous Reading and Writing No
Supports stat filesize, filemtime, filetype, file_exists, is_file, and is_dir elements only.
Supports unlink Yes
Supports rename Yes
Supports mkdir Yes
Supports rmdir Yes

Wrapper Summary {role="stream_wrapper"}

ENTITY

[!NOTE] FTPS is only supported when the openssl extension is enabled.

If the server does not support SSL, then the connection falls back to regular unencrypted ftp.

[!NOTE] Files may be appended via the ftp:// URL wrapper.

ENTITY

glob

glob://

Find pathnames matching pattern

ENTITY

The glob: stream wrapper.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Restricted by allow_url_include No
Allows Reading No
Allows Writing No
Allows Appending No
Allows Simultaneous Reading and Writing No
Supports stat No
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

ENTITY

Basic usage

<?php
// Loop over all *.php files in ext/spl/examples/ directory
// and print the filename and its size
$it = new DirectoryIterator("glob://ext/spl/examples/*.php");
foreach($it as $f) {
    printf("%s: %.1FK\n", $f->getFilename(), $f->getSize()/1024);
}
?>

   
tree.php: 1.0K
findregex.php: 0.6K
findfile.php: 0.7K
dba_dump.php: 0.9K
nocvsdir.php: 1.1K
phar_from_dir.php: 1.0K
ini_groups.php: 0.9K
directorytree.php: 0.9K
dba_array.php: 1.1K
class_tree.php: 1.8K

http

http://

https://

Accessing HTTP(s) URLs

ENTITY

Allows read-only access to files/resources via HTTP. By default, a HTTP 1.0 GET is used. A Host: header is sent with the request to handle name-based virtual hosts. If you have configured a user_agent string using your ENTITY file or the stream context, it will also be included in the request.

The stream allows access to the body of the resource; the headers are stored in the $http_response_header variable.

If it's important to know the URL of the resource where your document came from (after all redirects have been processed), you'll need to process the series of response headers returned by the stream.

The from directive will be used for the From: header if set and not overwritten by the ???.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen Yes
Allows Reading Yes
Allows Writing No
Allows Appending No
Allows Simultaneous Reading and Writing N/A
Supports stat No
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

ENTITY

Detecting which URL we ended up on after redirects

<?php
$url = 'http://www.example.com/redirecting_page.php';

$fp = fopen($url, 'r');

$meta_data = stream_get_meta_data($fp);
foreach ($meta_data['wrapper_data'] as $response) {

    /* Were we redirected? */
    if (strtolower(substr($response, 0, 10)) == 'location: ') {

        /* update $url with where we were redirected to */
        $url = substr($response, 10);
    }

}

?>

   

ENTITY

[!NOTE] HTTPS is only supported when the openssl extension is enabled.

HTTP connections are read-only; writing data or copying files to an HTTP resource is not supported.

Sending POST and PUT requests, for example, can be done with the help of HTTP Contexts.

ENTITY

$http_response_header

stream_get_meta_data

phar

phar://

PHP Archive

ENTITY

The phar:// stream wrapper. See Phar stream wrapper for a detailed description.

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Restricted by allow_url_include No
Allows Reading Yes
Allows Writing Yes
Allows Appending No
Allows Simultaneous Reading and Writing Yes
Supports stat Yes
Supports unlink Yes
Supports rename Yes
Supports mkdir Yes
Supports rmdir Yes

Wrapper Summary {role="stream_wrapper"}

ENTITY

php

php://

Accessing various I/O streams

ENTITY

PHP provides a number of miscellaneous I/O streams that allow access to PHP's own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr

php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

php://input

php://input is a read-only stream that allows you to read raw data from the request body. It can be opened and read as many times as needed. php://input is not available in POST requests with enctype="multipart/form-data" if enable_post_data_reading option is enabled.

php://output

php://output is a write-only stream that allows you to write to the output buffer mechanism in the same way as print and echo.

php://fd

php://fd allows direct access to the given file descriptor. For example, php://fd/3 refers to file descriptor 3.

php://memory and php://temp

php://memory and php://temp are read-write streams that allow temporary data to be stored in a file-like wrapper. One difference between the two is that php://memory will always store its data in memory, whereas php://temp will use a temporary file once the amount of data stored hits a predefined limit (the default is 2 MB). The location of this temporary file is determined in the same way as the sys_get_temp_dir function.

The memory limit of php://temp can be controlled by appending /maxmemory:NN, where NN is the maximum amount of data to keep in memory before using a temporary file, in bytes.

[!CAUTION] Some PHP extensions may require a standard IO stream, and may attempt to cast a given stream to a standard IO stream. This cast can fail for memory streams as it requires the C fopencookie function to be available. This C function is not available on Windows.

php://filter

php://filter is a kind of meta-wrapper designed to permit the application of filters to a stream at the time of opening. This is useful with all-in-one file functions such as readfile, file, and file_get_contents where there is otherwise no opportunity to apply a filter to the stream prior the contents being read.

The php://filter target takes the following parameters as part of its path. Multiple filter chains can be specified on one path. Please refer to the examples for specifics on using these parameters.

Name Description
resource=ENTITYstream to be filteredENTITY This parameter is required. It specifies the stream that you would like to filter.
read=ENTITYfilter list to apply to read chainENTITY This parameter is optional. One or more filter names can be provided here, separated by the pipe character (`
write=ENTITYfilter list to apply to write chainENTITY This parameter is optional. One or more filter names can be provided here, separated by the pipe character (`
ENTITYfilter list to apply to both chainsENTITY Any filter lists which are not prefixed by read= or write= will be applied to both the read and write chains as appropriate.

php://filter parameters {role="stream_wrapper"}

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Restricted by allow_url_include php://input, php://stdin, php://memory and php://temp only.
Allows Reading php://stdin, php://input, php://fd, php://memory and php://temp only.
Allows Writing php://stdout, php://stderr, php://output, php://fd, php://memory and php://temp only.
Allows Appending php://stdout, php://stderr, php://output, php://fd, php://memory and php://temp only. (Equivalent to writing)
Allows Simultaneous Reading and Writing php://fd, php://memory and php://temp only.
Supports stat No. However, php://memory and php://temp support fstat.
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No
Supports stream_select php://stdin, php://stdout, php://stderr, php://fd and php://temp only.

Wrapper Summary (for php://filter, refer to the summary of the wrapper being filtered) {role="stream_wrapper"}

ENTITY

php://temp/maxmemory

This optional parameter allows setting the memory limit before php://temp starts using a temporary file.

<?php
// Set the limit to 5 MB.
$fiveMBs = 5 * 1024 * 1024;
$fp = fopen("php://temp/maxmemory:$fiveMBs", 'r+');

fputs($fp, "hello\n");

// Read what we have written.
rewind($fp);
echo stream_get_contents($fp);
?>

   

php://filter/resource=ENTITYstream to be filteredENTITY

This parameter must be located at the end of your php://filter specification and should point to the stream which you want filtered.

<?php
/* This is equivalent to simply:
  readfile("http://www.example.com");
  since no filters are actually specified */

readfile("php://filter/resource=http://www.example.com");
?>

   

php://filter/read=ENTITYfilter list to apply to read chainENTITY

This parameter takes one or more filternames separated by the pipe character |.

<?php
/* This will output the contents of
  www.example.com entirely in uppercase */
readfile("php://filter/read=string.toupper/resource=http://www.example.com");

/* This will do the same as above
  but will also ROT13 encode it */
readfile("php://filter/read=string.toupper|string.rot13/resource=http://www.example.com");
?>

   

php://filter/write=ENTITYfilter list to apply to write chainENTITY

This parameter takes one or more filternames separated by the pipe character |.

<?php
/* This will filter the string "Hello World"
  through the rot13 filter, then write to
  example.txt in the current directory */
file_put_contents("php://filter/write=string.rot13/resource=example.txt","Hello World");
?>

   

php://memory and php://temp are not reusable

php://memory and php://temp are not reusable, i.e. after the streams have been closed there is no way to refer to them again.

<?php
file_put_contents('php://memory', 'PHP');
echo file_get_contents('php://memory'); // prints nothing

   

php://input to read JSON data from the request body

This example demonstrates how to read raw JSON data from POST, PUT and PATCH requests using php://input.

<?php
$input = file_get_contents("php://input");
$json_array = json_decode(
  json: $input,
  associative: true,
  flags: JSON_THROW_ON_ERROR
);

echo "Received JSON data: ";
print_r($json_array);
?>

   

rar

rar://

RAR

ENTITY

The wrapper takes the url encoded path to the RAR archive (relative or absolute), an optional asterisk (*), an optional number sign (#) and an optional url encoded entry name, as stored in the archive. Specifying an entry name requires the number sign; a leading forward slash in the entry name is optional.

This wrapper can open both files and directories. When opening directories, the asterisk sign forces the directory entries names to be returned unencoded. If it's not specified, they will be returned url encoded – the reason for this is to allow the wrapper to be correctly used with built-in functionality like the RecursiveDirectoryIterator in the presence of file names that seem like url encoded data.

If the pound sign and the entry name part are not included, the root of the archive will be displayed. This differs from regular directories in that the resulting stream will not contain information such as the modification time, as the root directory is not stored in an individual entry in the archive. The usage of the wrapper with RecursiveDirectoryIterator requires the number sign to be included in the URL when accessing the root, so that the URLs of the children may be constructed correctly.

[!NOTE] In order to use the rar:// wrapper, the rar extension available from ENTITY must be installed.

rar:// Available since PECL rar 3.0.0

ENTITY

ENTITY

Attribute Supported
Restricted by allow_url_fopen No
Restricted by allow_url_include No
Allows Reading Yes
Allows Writing No
Allows Appending No
Allows Simultaneous Reading and Writing No
Supports stat Yes
Supports unlink No
Supports rename No
Supports mkdir No
Supports rmdir No

Wrapper Summary {role="stream_wrapper"}

Name Usage Default
open_password The password used to encrypt the headers of the archive, if any. WinRAR will encrypt all the files with the same password as the headers password when the later is present, so for archives with encrypted headers, file_password will be ignored.
file_password The password used to encrypt a file, if any. If the headers are also encrypted, this option will be ignored in favor of open_password. The reason there are two options is to cover the possibility of supporting archives with different headers and file passwords, should those archives arise. Note that if the archive does not have its headers encrypted, open_password will be ignored and this option must be used instead.
volume_callback A callback to determine the path of missing volumes. See RarArchive::open for more information.

Context options {role="stream_wrapper"}

ENTITY

Traversing a RAR archive

<?php

class MyRecDirIt extends RecursiveDirectoryIterator {
    function current() {
        return rawurldecode($this->getSubPathName()) .
            (is_dir(parent::current())?" [DIR]":"");
    }
}

$f = "rar://" . rawurlencode(dirname(__FILE__)) .
    DIRECTORY_SEPARATOR . 'dirs_and_extra_headers.rar#';

$it = new RecursiveTreeIterator(new MyRecDirIt($f));

foreach ($it as $s) {
    echo $s, "\n";
}
?>

   

ENTITY

|-allow_everyone_ni [DIR]
|-file1.txt
|-file2_אּ.txt
|-with_streams.txt
\-אּ [DIR]
  |-אּ\%2Fempty%2E [DIR]
  | \-אּ\%2Fempty%2E\file7.txt
  |-אּ\empty [DIR]
  |-אּ\file3.txt
  |-אּ\file4_אּ.txt
  \-אּ\אּ_2 [DIR]
    |-אּ\אּ_2\file5.txt
    \-אּ\אּ_2\file6_אּ.txt

Opening an encrypted file (header encryption)

<?php
$stream = fopen("rar://" .
    rawurlencode(dirname(__FILE__)) . DIRECTORY_SEPARATOR .
    'encrypted_headers.rar' . '#encfile1.txt', "r", false,
    stream_context_create(
        array(
            'rar' =>
                array(
                    'open_password' => 'samplepassword'
                )
            )
        )
    );
var_dump(stream_get_contents($stream));
/* creation and last access date is opt-in in WinRAR, hence most
 * files don't have them */
var_dump(fstat($stream));
?>

   

ENTITY

string(26) "Encrypted file 1 contents."
Array
(
    [0] => 0
    [1] => 0
    [2] => 33206
    [3] => 1
    [4] => 0
    [5] => 0
    [6] => 0
    [7] => 26
    [8] => 0
    [9] => 1259550052
    [10] => 0
    [11] => -1
    [12] => -1
    [dev] => 0
    [ino] => 0
    [mode] => 33206
    [nlink] => 1
    [uid] => 0
    [gid] => 0
    [rdev] => 0
    [size] => 26
    [atime] => 0
    [mtime] => 1259550052
    [ctime] => 0
    [blksize] => -1
    [blocks] => -1
)

ssh2

ssh2://

Secure Shell 2

ENTITY

ssh2.shell:// ssh2.exec:// ssh2.tunnel:// ssh2.sftp:// ssh2.scp:// (PECL)

[!NOTE] In order to use the ssh2.*:// wrappers, the SSH2 extension available from ENTITY must be installed.

In addition to accepting traditional URI login details, the ssh2 wrappers will also reuse open connections by passing the connection resource in the host portion of the URL.

ENTITY

ENTITY

Attribute ssh2.shell ssh2.exec ssh2.tunnel ssh2.sftp ssh2.scp
Restricted by allow_url_fopen Yes Yes Yes Yes Yes
Allows Reading Yes Yes Yes Yes Yes
Allows Writing Yes Yes Yes Yes No
Allows Appending No No No Yes (When supported by server) No
Allows Simultaneous Reading and Writing Yes Yes Yes Yes No
Supports stat No No No Yes No
Supports unlink No No No Yes No
Supports rename No No No Yes No
Supports mkdir No No No Yes No
Supports rmdir No No No Yes No

Wrapper Summary {role="stream_wrapper"}

Name Usage Default
session Preconnected ssh2 resource to be reused
sftp Preallocated sftp resource to be reused
methods Key exchange, hostkey, cipher, compression, and MAC methods to use
callbacks
username Username to connect as
password Password to use with password authentication
pubkey_file Name of public key file to use for authentication
privkey_file Name of private key file to use for authentication
env Associate array of environment variables to set
term Terminal emulation type to request when allocating a pty
term_width Width of terminal requested when allocating a pty
term_height Height of terminal requested when allocating a pty
term_units Units to use with term_width and term_height SSH2_TERM_UNIT_CHARS

Context options {role="stream_wrapper"}

ENTITY

Opening a stream from an active connection

<?php
$session = ssh2_connect('example.com', 22);
ssh2_auth_pubkey_file($session, 'username', '/home/username/.ssh/id_rsa.pub',
                                            '/home/username/.ssh/id_rsa', 'secret');
$stream = fopen("ssh2.tunnel://$session/remote.example.com:1234", 'r');
?>

   

This $session variable must be kept available!

In order to use the ssh2.*://$session wrappers, the $session resource variable must be kept. The code below will not have the desired effect:

<?php
$session = ssh2_connect('example.com', 22);
ssh2_auth_pubkey_file($session, 'username', '/home/username/.ssh/id_rsa.pub',
                                            '/home/username/.ssh/id_rsa', 'secret');
$connection_string = "ssh2.sftp://$session/";
unset($session);
$stream = fopen($connection_string . "path/to/file", 'r');
?>

   

unset() closes the session, because $connection_string does not hold a reference to the $session variable, just a string cast derived from it. This also happens when the unset is implicit because of leaving scope (like in a function).