tolerant-php-parser/php-langspec/spec/14-classes.md

74 KiB
Исходник Ответственный История

#Classes

##General

A class is a type that may contain zero or more explicitly declared members, which can be any combination of class constants; data members, called properties; and function members, called methods. The ability to add properties to an instance at runtime is described in dynamic members section. An object (often called an instance) of a class type is created (i.e., instantiated) via the new operator.

PHP supports inheritance, a means by which a derived class can extend and specialize a single base class (also called parent). Classes in PHP are not all derived from a common ancestor. An abstract class is a base type intended for derivation, but which cannot be instantiated directly. A concrete class is a class that is not abstract. A final class is one from which other classes cannot be derived.

A class may implement one or more interfaces, each of which defines a contract. Interfaces may have method and constants, but not properties.

A class can use one or more traits, which allows a class to have some of the benefits of multiple inheritance.

A constructor is a special method that is used to initialize an instance immediately after it has been created. A destructor is a special method that is used to free resources when an instance is no longer needed. Other special methods exist; they are described in special method section.

The members of a class each have a default or explicitly declared visibility, which determines what source code can access them. A member with private visibility may be accessed only from within its own class. A member with protected visibility may be accessed only from within its own class and from classes above and below it in the inheritance chain. Access to a member with public visibility is unrestricted.

The signature of a method is a combination of that method's class name, name, and argument list, including argument type declarations and indication for arguments passed byRef, and whether the resulting value is returned byRef.

Methods and properties implemented in a base class can be overridden in a derived class by redeclaring them with the compatible signature (see below). If the overriding method does not have a compatible signature, a non-fatal error is issued but the override is still permitted. It is not recommended to use incompatible signatures for overriding methods.

When an instance is allocated, new returns a handle that points to that object. As such, assignment of a handle does not copy the object itself. (See cloning objects for a discussion of shallow and deep copying).

While PHP supports anonymous class types, such a type cannot be declared using class-declaration. Instead, it must be specified at the time of instantiation; that is, as part of an object-creation-expression.

##Class Declarations

Syntax

  class-declaration:
    class-modifieropt  class  name   class-base-clauseopt  class-interface-clauseopt   {   class-member-declarationsopt }

  class-modifier:
    abstract
    final

  class-base-clause:
    extends  qualified-name

  class-interface-clause:
    implements  qualified-name
    class-interface-clause  ,  qualified-name

Defined elsewhere

Constraints

name must be a valid name, and must not be self, parent, or a reserved keyword.

qualified-name must be a valid qualified-name and its name element must not be self, parent, or a reserved keyword.

A class-declaration containing any class-member-declarations that have the modifier abstract must itself have an abstract class-modifier.

class-base-clause must not name a final class.

qualified-name in class-base-clause must name an existing class.

A class must not be derived directly or indirectly from itself.

A concrete class must implement each of the methods from all the interfaces specified in class-interface-clause.

For each interface method, the corresponding implementing method must be compatible with the interface method, including the following:

  • If the interface method is defined as returning byRef, the implementing method should also return byRef.
  • If the interface method is variadic, the implementing method must also be variadic (see also below).
  • The number of required (i.e. having no defaults) arguments of the implementing methods can not be more than the number of required arguments of the interface method (adding non-optional arguments is not allowed).
  • The overall number of arguments for the implementing method should be at least the number of the arguments of the interface method (removing arguments is not allowed).
  • Each argument of the implementing method must be compatible with corresponding argument of the prototype method.
  • If the interface method defines the return type, the implementing method must have the same return type.

Compatible arguments are defined as follows:

  • Parameter names do not matter.
  • If the argument is optional (has default) in the interface, it should be optional in the implementation. However, implementation can provide a different default value.
  • byRef argument requires byRef implementation, and non-byRef argument can not have byRef implementation.
  • For no argument type, only declaration with no type is compatible.
  • For typed argument, only argument with the same type is compatible.
  • For variadic arguments, the definition of the variadic (last) argument should be compatible as per above. The implementation can define additional optional arguments before the variadic argument, but these arguments should be compatible with the variadic argument on the interface method.

qualified-name in class-interface-clause must name an interface type.

Semantics

A class-declaration defines a class type by the name name. Class names are case-insensitive.

The abstract modifier declares a class usable only as a base class; the class cannot be instantiated directly. An abstract class may contain one or more abstract members, but it is not required to do so. When a concrete class is derived from an abstract class, the concrete class must include an implementation for each of the abstract members it inherits. The implementations of abstract methods must have compatible signatures, incompatible implementations are not permitted.

The final modifier prevents a class from being used as a base class.

The optional class-base-clause specifies the one base class from which the class being defined is derived. In such a case, the derived class inherits all the members from the base class.

The optional class-interface-clause specifies the one or more interfaces that are implemented by the class being defined.

Examples

abstract class Vehicle
{
  public abstract function getMaxSpeed();
  ...
}
abstract class Aircraft extends Vehicle
{
  public abstract function getMaxAltitude();
  ...
}
class PassengerJet extends Aircraft
{
  public function getMaxSpeed()
  {
    // implement method
  }
  public function getMaxAltitude()
  {
    // implement method
  }
  ...
}
$pj = new PassengerJet(...);
echo "\$pj's maximum speed: " . $pj->getMaxSpeed() . "\n";
echo "\$pj's maximum altitude: " . $pj->getMaxAltitude() . "\n";
// -----------------------------------------
final class MathLibrary
{
  private function MathLibrary() {} // disallows instantiation
  public static function sin() { ... }
  // ...
}
$v = MathLibrary::sin(2.34);
// -----------------------------------------
interface MyCollection
{
        function put($item);
        function get();
}
class MyList implements MyCollection
{
  public function put($item)
  {
    // implement method
  }
  public function get()
  {
    // implement method
  }
  ...
}

##Class Members

Syntax

  class-member-declarations:
    class-member-declaration
    class-member-declarations   class-member-declaration

   class-member-declaration:
     class-const-declaration
     property-declaration
     method-declaration
     constructor-declaration
     destructor-declaration
     trait-use-clause

Defined elsewhere

Semantics

The members of a class are those specified by its class-member-declarations, and the members inherited from its base class.

A class may contain the following members:

  • Constants – the constant values associated with the class.
  • Properties – the variables of the class.
  • Methods – the computations and actions that can be performed by the class.

Some methods have special semantics, such as:

Members can be imported from one or more traits via trait-use-clauses.

The class can also have dynamic members which are not part of the class definition.

Methods and properties can either be static or instance members. A static member is declared using static. An instance member is one that is not static. The name of a static or instance member can never be used on its own; it must always be used as the right-hand operand of the scope resolution operator or the member selection operator.

Each instance of a class contains its own, unique set of instance properties of that class. An instance member is accessed via the -> operator. In contrast, a static property designates exactly one VSlot for its class, which does not belong to any instance, per se. A static property exists whether or not any instances of that class exist. A static member is accessed via the :: operator.

When any instance method operates on a given instance of a class, within that method that object can be accessed via $this. As a static method does not operate on a specific instance, it has no $this.

Examples

class Point
{
  private static $pointCount = 0;     // static property

  private $x;             // instance property
  private $y;             // instance property

  public static function getPointCount()    // static method
  {
    return self::$pointCount;     // access static property
  }
  public function move($x, $y)        // instance method
  {
    $this->x = $x;
    $this->y = $y;
  }
  public function __construct($x = 0, $y = 0) // instance method
  {
    $this->x = $x;          // access instance property
    $this->y = $y;          // access instance property
    ++self::$pointCount;    // access static property
  }
  public function __destruct()      // instance method
  {
    --self::$pointCount;        // access static property
    ...
  }
  ...
}
echo "Point count = " . Point::getPointCount() . "\n";
$cName = 'Point';
echo "Point count = " . $cName::getPointCount() . "\n";

##Dynamic Members

Initially, the instance only has properties that are declared explicitly in its class's definition. However, properties can be added to and removed from the instance at runtime. Static properties of a class can not be changed at runtime, attempt to access non-existing static property results in a fatal error. Runtime-created properties always have public visibility.

The class can also define special methods for dynamic members - methods and properties. This facility uses the same syntax to access the members as the regular members, but instead of accessing actual properties and methods the engine will use special methods to simulate the access.

In the case of dynamic properties, if a class makes provision to do so by defining a series of special methods, it can deal with the allocation and management of storage for those properties, by storing them in another object or in a database, for example. For dynamic methods, both static and non-static methods can be handled by special methods.

Consider the following scenario, which involves dynamic properties:

class Point { ... } // has no public property "color", but has made
                    // provision to support dynamic properties.
$p = new Point(10, 15);
$p->color = "red"; // create/set the dynamic property "color"
$v = $p->color;    // get the dynamic property "color"
isset($p->color);  // test if the dynamic property "color" exists
unset($p->color);  // remove the dynamic property "color"

Dynamic property handling is invoked when a property with specified name name that is not currently visible (because it is hidden or it does not exist). If the property is used in a modifiable lvalue context (as with the assignment of "red"), the Engine generates a call to the instance method __set. This method treats that name as designating a dynamic property of the instance being operated on, and sets its value to "red", creating the property, if necessary. Similarly, in a non-lvalue context, (as with the assignment of color to $v), the Engine generates a call to the instance method __get, which treats that name as designating a dynamic property of the instance being operated on, and gets its value. In the case of the call to the intrinsic isset, this generates a call to the instance method __isset, while a call to the intrinsic unset generates a call to the instance method __unset. By defining these four special methods, the implementer of a class can control how dynamic properties are handled.

The Engine will call the methods only if they are defined, if they are not defined, no error is produced and default behavior is used.

In the case of a dynamic method, if a call to an undefined instance method is performed and the instance has __call method, then this method is called. Otherwise, as per default, a fatal error is produced. If a static call to an undefined class method is performed, and the class defines a __callStatic method, this method is called. Otherwise, as per default, a fatal error is produced. In both cases, the return value of the call is the return value of the method called.

Consider the following code fragment, in which class Widget has neither an instance method called iMethod nor a static method called sMethod, but that class has made provision to deal with dynamic methods:

$obj = new Widget;
$obj->iMethod(10, TRUE, "abc");
Widget::sMethod(NULL, 1.234);

The call to iMethod is treated as if it were

$obj->__call('iMethod', array(10, TRUE, "abc"))

and the call to sMethod is treated as if it were

Widget::__callStatic('sMethod', array(NULL, 1.234))

##Constants

Syntax

  const-declaration:
    const   const-elements   ;

  class-const-declaration:
    visibility-modifieropt   const   const-elements   ;

  const-elements:
    const-element
    const-elements   const-element

  const-element:
    name   =   constant-expression

Defined elsewhere

Constraints:

A const-declaration must only appear at the top level of a script, and must not redefine an existing c-constant.

A class-const-declaration must be inside a class-declaration or interface-declaration.

A class constant must not have a static specifier.

Semantics:

A const-declaration defines a c-constant.

If visibility-modifier for a class constant is omitted, public is assumed. The visibility-modifier applies to all constants defined in the const-elements list.

All constants are implicitly static.

Examples:

const MIN_VAL = 20;
const LOWER = MIN_VAL;
// -----------------------------------------
class Automobile
{
  const DEFAULT_COLOR = "white";
  public DEFAULT_BRAND = 'benz';
  protected WHEEL_NUM = 4;
  private PRIVATE_CONST = 'const';
  ...
}
$col = Automobile::DEFAULT_COLOR;

##Properties

Syntax

  property-declaration:
    property-modifier   property-elements   ;

  property-modifier:
    var
    visibility-modifier   static-modifieropt
    static-modifier   visibility-modifieropt

  visibility-modifier:
    public
    protected
    private

  static-modifier:
    static

  property-elements:
    property-element
    property-elements   property-element

  property-element:
    variable-name   property-initializeropt   ;

  property-initializer:
    =  constant-expression

Defined elsewhere

Semantics

A property-declaration defines one or more instance or static properties.

If visibility-modifier is omitted, public is assumed. The var modifier implies public visibility. The static modifier defines the member as a static member.

The property-initializer for instance properties is applied prior to the class's constructor being called.

An instance property that is visible may be unset, in which case, the property is actually removed from that instance.

Examples

class Point
{
  private static $pointCount = 0; // static property with initializer

  private $x; // instance property
  private $y; // instance property
  ...

}

##Methods

Syntax

  method-declaration:
    method-modifiersopt   function-definition
    method-modifiers   function-definition-header  ;

  method-modifiers:
    method-modifier
    method-modifiers   method-modifier

  method-modifier:
    visibility-modifier
    static-modifier
    class-modifier

Defined elsewhere

Constraints

The method-modifiers preceding a function-definition must not contain the abstract modifier.

The method-modifiers preceding a function-definition-header must contain the abstract modifier.

A method must not have the same modifier specified more than once. A method must not have more than one visibility-modifier. A method must not have both the modifiers abstract and private, or abstract and final.

Semantics

A method-declaration defines an instance or static method. A method is a function that is defined inside a class. However, the presence of abstract indicates an abstract method, in which case, no implementation is provided. The absence of abstract indicates a concrete method, in which case, an implementation is provided.

Method names are case-insensitive.

The presence of final indicates the method cannot be overridden in a derived class.

If visibility-modifier is omitted, public is assumed.

Examples

See class members for examples of instance and static methods. See class declarations for examples of abstract methods and their subsequent definitions.

##Constructors

Syntax

  constructor-declaration:
    method-modifiers  function &opt   __construct  (  parameter-declaration-listopt  )  compound-statement

Defined elsewhere

Constraints

An overriding constructor in a derived class must have the same or a less-restricted visibility than the one in the base class.

method-modifiers can not contain static.

Semantics

A constructor is a specially named instance method that is used to initialize an instance immediately after it has been created. Any instance properties having no initializers and not explicitly initialized by a constructor take on the value NULL. A constructor can return a result, by value or byRef. A constructor cannot be abstract or static.

The class does not have to define a constructor.

If visibility-modifier is omitted, public is assumed. A private constructor inhibits the creation of an instance of the class type except by methods of the same class.

Constructors can be overridden in a derived class by redeclaring them. However, an overriding constructor need not have the same or compatible signature as one defined in the base class.

Constructors are called by object-creation-expression and from within other (derived class) constructors.

If classes in a derived-class hierarchy have constructors, it is the responsibility of the constructor at each level to call the constructor in its base-class explicitly, using the notation parent::__construct(...). If a constructor calls its base-class constructor, it is recommended to do so as the first statement in compound-statement, so the object hierarchy is built from the bottom-up. A constructor should not call its base-class constructor more than once. A call to a base-class constructor searches for the nearest constructor in the class hierarchy. Not every level of the hierarchy needs to have a constructor.

Examples

class Point
{
  private static $pointCount = 0;
  private $x;
  private $y;
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
    ++self::$pointCount;
  }
  public function __destruct()
  {
    --self::$pointCount;
    ...
  }
  ...
}
// -----------------------------------------
class MyRangeException extends Exception
{
  public function __construct($message, ...)
  {
    parent::__construct($message);
    ...
  }
  ...
}

##Destructors

Syntax

  destructor-declaration:
    method-modifiers  function  &opt  __destruct  ( ) compound-statement

Defined elsewhere

Constraints

method-modifiers can not contain static.

Semantics

A destructor is a special-named instance method that is used to free resources when an instance is no longer needed. The destructors for instances of all classes are called automatically once there are no handles pointing to those instances or in some unspecified order during program shutdown. Like any method, a destructor can return a result by value or byRef. A destructor cannot be static.

Destructors are called by the Engine or from within other (derived class) destructors.

If classes in a derived-class hierarchy have destructors, it is the responsibility of the destructor at each level to call the destructor in the base-class explicitly, using the notation parent::__destruct(). If a destructor calls its base-class destructor, it is recommended to do so as the last statement in compound-statement, so the object hierarchy is destructed from the top-down. A destructor should not call its base-class destructor more than once. A call to a base-class destructor searches for the nearest destructor in the class hierarchy. Not every level of the hierarchy need have a destructor. A private destructor inhibits destructor calls from derived classes.

Examples

See constructors section for an example of a constructor and destructor.

##Inheritance

When a class extends another class it can override members of the parent class by declaring a member with the same name. Only properties and methods can be overridden.

Visibility of the overridden member can not be made more restrictive, only more permissive (from private to protected to public).

When a private member is overridden, the methods of the defining class still have access to the original private member, however non-static public and protected members are shared across the inheritance chain.

When a method is overridden, the signature of the overriding method should be compatible with the signature of the original method, by the same rule as if the original method belonged to the interface and the overriding method belonged to an implementation. If an implemented method is overridden with an incompatible method, a non-fatal error is issued, however the override is still accepted by the engine. The use of incompatible overrides is not recommended.

##Methods with Special Semantics

###General

If a class contains a definition for a method having one of the following names, that method must have the prescribed visibility, signature, and semantics:

Method Name Description
__call Calls a dynamic method in the context of an instance method call.
__callStatic Calls a dynamic method in the context of a static method call.
__clone Typically used to make a deep copy of an object.
__construct A constructor.
__debugInfo Produce debugging information for the object.
__destruct A destructor.
__get Retrieves the value of a given dynamic property.
__invoke Called when an object is called as a function (e.g. $a()).
__isset Reports if a given dynamic property exists.
__set Sets the value of a given dynamic property.
__set_state Used by export function var_export to restore the state of the object.
__sleep Executed before serialization of an instance of this class.
__toString Returns a string representation of the instance on which it is called.
__unset Removes a given dynamic property.
__wakeup Executed after unserialization of an instance of this class.

In general, method names beginning with __ are reserved for special methods. The code should not define methods with names beginning with __ unless it is one of the special methods described here.

Note that while syntax definitions below use the non-abstract syntax in the method definition, the special methods, like any methods, can be declared abstract. In this case the definition does not actually define a special method but defines that an overriding concrete class must declare one. Nevertheless, the constraints on special methods must still be followed in such definitions.

###Method __call

Syntax

  method-modifiers function  __call  (  $name  ,  $arguments  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method can not be static and must have public visibility.

The arguments passed to this method must not be passed byRef.

Semantics

This instance method is called to invoke the dynamic method designated by $name using the arguments specified by the elements of the array designated by $arguments. It can return any value deemed appropriate.

Typically, __call is called implicitly, when the -> operator is used to call an instance method that is not visible.

While __call can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression p->m(...), where p is an instance and m is an instance-method name. If m is the name of a visible method, p->m(...) does not result in __call's being called. Instead, the visible method is used. On the other hand, the expression p->__call('m',array(...)) always calls the named dynamic method, ignoring the fact that a visible method having the same name might exist. If m is not the name of a visible method, the two expressions are equivalent; that is; when handling p->m(...), if no visible method by that name is found, a dynamic method is assumed, and __call is called.

While the name source token has a prescribed syntax, there are no restrictions on the content of the dynamic method name designated by $name. Any source character is allowed here.

Examples

class Widget
{
  public function __call($name, $arguments)
  {
    // using the method name and argument list, redirect/process
    // the method call, as desired.
  }
  ...
}
$obj = new Widget;
$obj->iMethod(10, TRUE, "abc"); // $obj->__call('iMethod', array(...))

###Method __callStatic

Syntax

  method-modifiers  function  __callStatic  (  $name  ,  $arguments  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must contain static and must define public visibility.

The arguments passed to this method must not be passed byRef.

Semantics

This static method is called to invoke the dynamic method designated by $name using the arguments specified by the elements of the array designated by $arguments. It can return any value deemed appropriate.

Typically, __callStatic is called implicitly, when the :: operator is used to call a static method that is not visible.

While __callStatic can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression C::m(...), where C is a class and m is a static-method name. If m is the name of a visible method, C::m(...) does not result in __callStatic's being called. Instead, the visible method is used. On the other hand, the expression C::__callStatic('m',array(...)) always calls the named dynamic method, ignoring the fact that a static visible method having the same name might exist. If m is not the name of a visible method, the two expressions are equivalent; that is; when handling C::m(...), if no visible method by that name is found, a dynamic method is assumed, and __callStatic is called.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic method name designated by $name. Any source character is allowed here.

Examples

class Widget
{
    public static function __callStatic($name, $arguments)
    {
      // using the method name and argument list, redirect/process\
      // the method call, as desired.
    }
    ...
}

Widget::sMethod(NULL, 1.234); // Widget::__callStatic('sMethod', array(...))

###Method __clone

Syntax

  method-modifiers  function  __clone  (  )  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method is called by the clone operator, typically to make a deep copy of the the instance on which it is called. Method __clone cannot be called directly by the program.

Consider a class Employee, from which is derived a class Manager. Let us assume that both classes contain properties that are objects. To make a copy of a Manager object, its __clone method is called to do whatever is necessary to copy the properties for the Manager class. That method should, in turn, call the __clone method of its parent class, Employee, so that the properties of that class can also be copied (and so on, up the derived-class hierarchy).

To clone an object, the clone operator makes a shallow copy of the object on which it is called. Then, if the class of the instance being cloned has a method called __clone, that method is called to make a deep copy. Method __clone cannot be called directly from outside a class; it can only be called by name from within a derived class, using the notation parent::__clone(). This method can return a value; however, if it does so and control returns directly to the point of invocation via the clone operator, that value will be ignored. The value returned to a parent::__clone() call can, however, be retrieved.

While cloning creates a new object, it does so without using a constructor, in which case, code may need to be added to the __clone method to emulate what happens in a corresponding constructor. (See the Point example below).

An implementation of __clone should factor in the possibility of an instance having dynamic properties.

Examples

class Employee
{
  ...
  public function __clone()
  {
    // do what it takes here to make a copy of Employee object properties
  }
}
class Manager extends Employee
{
  ...
  public function __clone()
  {
    parent::__clone(); // request cloning of the Employee properties

    // do what it takes here to make a copy of Manager object properties
  }
  ...
}
// -----------------------------------------
class Point
{
  private static $pointCount = 0;
  public function __construct($x = 0, $y = 0)
  {
    ...
    ++self::$pointCount;
  }
  public function __clone()
  {
    ++self::$pointCount; // emulate the constructor
  }
  ...
}
$p1 = new Point;  // created using the constructor
$p2 = clone $p1;  // created by cloning

###Method __debugInfo

Syntax

  method-modifiers function  __debugInfo  (  )   compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

The function should return array.

Semantics

This method allows the class to supply debugging information for the object, which can be used as the source of information for var_dump().

Example

class File {
  // "Resource(stream)" isn't all that useful
  private $fp;

  // But all the stream meta data is
  public function __debugInfo() {
    return $this->fp ? stream_get_meta_data($fp) : [];
  }

  public function open($filename, $mode = 'r'){
    $this->fp = fopen($filename, $mode);
  }
}

$f = new File;
var_dump($f); // object(File)#1 { }
$f->open('http://php.net');
var_dump($f);
/*
object(File)#1 {
  ["wrapper_type"]=>
  string(4) "http"
  ["stream_type"]=>
  string(10) "tcp_socket"
  etc...
*/

###Method __get

Syntax

  method-modifiers function  &opt  __get  (  $name  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method gets the value of the dynamic property designated by $name. It is up to the implementor to define the return value.

Typically, __get is called implicitly, when the -> operator is used in a non-lvalue context and the named property is not visible.

While __get can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression $v = $p->m, where p is an instance and m is a property name. If m is the name of a visible property, p->m does not result in __get's being called. Instead, the visible property is used. On the other hand, the expression p->__get('m') always gets the value of the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed, and __get is called.

Consider the expression $v = $p->m = 5, where m is a dynamic property. While __set is called to assign the value 5 to that property, __get is not called to retrieve the result after that assignment is complete.

If the implementation wants the caller to be able to modify the contents of the returned value (such as returning an array which can be modified by caller, and the modifications are reflected in the dynamic property), __get should return byRef.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __get($name)
    {
        if (array_key_exists($name, $this->dynamicProperties))
        {
            return $this->dynamicProperties[$name];
        }

        // no-such-property error handling goes here
        return NULL;
    }
  ...
}

Implementation Notes

Consider the following class, which does not contain a property called prop:

class C
{
  public function __get($name)
  {
    return $this->$name;    // must not recurse
  }
  ...
}
$c = new C;
$x = $c->prop;

As no property (dynamic or otherwise) by the name prop exists in the class and a __get method is defined, this looks look a recursive situation. However, the implementation must not allow that. The same applies to seemingly self-referential implementations of __set, __isset, and __unset. Only one iteration of the dynamic resolution is performed per-property, and the special method is called only once per property name.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

###Method __invoke

Syntax

  method-modifiers  function  __invoke  ( parameter-declaration-listopt  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method allows an instance to be used with function-call notation. An instance whose class provides this method will also return TRUE when passed to is_callable.

When an instance is called as a function, the argument list used is made available to __invoke, whose return value becomes the return value of the initial function call.

Examples

class C
{
  public function __invoke($p)
  {
    ...
    return ...;
  }
  ...
}
$c = new C;
is_callable($c) // returns TRUE
$r = $c(123);   // becomes $r = $c->__invoke(123);

###Method __isset

Syntax

  method-modifiers  function  __isset  (  $name  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

If the dynamic property designated by $name exists, this instance method returns TRUE; otherwise, FALSE is returned. The speficis of how existance of the dynamic property is determined is left to the implementor of the method.

Typically, __isset is called implicitly, when the intrinsic isset or intrinsic empty is called with an argument that designates a property that is not visible.

While __isset can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression isset($p->m), where p is an instance and m is a property name. If m is the name of a visible property, __isset is not called. Instead, the visible property is used. On the other hand, the expression p->__isset('m') always tests for the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __isset($name)
    {
        return isset($this->dynamicProperties[$name]);
    }
  ...
}

Implementation Notes

See the Implementation Notes for __get.

###Method __set

Syntax

  method-modifiers  function  __set  (  $name  ,  $value  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

This instance method sets the value of the dynamic property designated by $name to $value. No value is expected to be returned.

Typically, __set is called implicitly, when the -> operator is used in a modifiable lvalue context and the named property is not visible.

While __set can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression p->m = 5, where p is an instance and m is a property name. If m is the name of a visible property, p->m does not result in __set's being called. Instead, the visible property is used. On the other hand, the expression p->__set('m',5) always sets the value of the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m, if no visible property by that name is found, a dynamic property is assumed, and __set is called.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __set($name, $value)
    {
        $this->dynamicProperties[$name] = $value;
    }
  ...
}
// -----------------------------------------
class X
{
    public function __destruct() { ... }
}
$p = new Point(5, 9);
$p->thing = new X;  // set dynamic property "thing" to instance with destructor
...
// at the end of the program, p->thing's destructor is called

Implementation Notes

See the Implementation Notes for __get.

###Method __set_state

Syntax

  method-modifiers  function  __set_state  ( array  $properties  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must contain static and must define public visibility.

Semantics

This function supports the library function var_export when it is given an instance of this class type. var_export takes a variable and produces a string representation of that variable as valid PHP code suitable for use with the intrinsic eval.

For an object, the string returned by var_export has the following general format:

classname::__set_state(array('prop1' => value, ..., 'propN' => value , ))

where the property names prop1 through propN do not include a leading dollar ($). This string contains a call to the __set_state method even if no such method is defined for this class or in any of its base classes, in which case, a subsequent call to eval using this string will produce a fatal error. To allow the string to be used with eval, the method __set_state must be defined, and it must create a new instance of the class type, initialize its instance properties using the key/value pairs in $properties, and it must return that new object.

When extending the class with __set_state method, one should override the method, otherwise a call to it will look for such a method in the base class hierarchy, and that method will return an instance of the associated base class, not of the class on which it was invoked. Usage of static allows late static binding to produce the instance of an appropriate class.

If a derived class defines a __set_state method, but any base class has instance properties that are not visible within that method, that method must invoke parent's __set_state as well, but that can require support from a base class. See the second example below.

Examples

class Point
{
  private $x;
  private $y;
  static public function __set_state(array $properties)
  {
    $p = new Point;
    $p->x = $properties['x'];
    $p->y = $properties['y'];
    return $p;
  }
  ...
}
$p = new Point(3, 5);
$v = var_export($p, TRUE);  // returns string representation of $p

The string produced looks something like the following:

"Point::__set_state(array(
   'x' => 3,
   'y' => 5,
))"
eval('$z = ' . $v . ";"); // execute the string putting the result in $z
echo "Point \$z is $z\n"; // Point $z is (3,5)
// -----------------------------------------
class B // base class of D
{
  private $bprop;
  public function __construct($p)
  {
    $this->bprop = $p;
  }
  static public function __set_state(array $properties)
  {
    $b = new static($properties['bprop']);  // note the static
    return $b;
    // Because of the "new static", the return statement
    //   returns a B when called in a B context, and
    //   returns a D when called in a D context
  }
}
class D extends B
{
  private $dprop = 123;
  public function __construct($bp, $dp = NULL)
  {
    $this->dprop = $dp;
    parent::__construct($bp);
  }
  static public function __set_state(array $properties)
  {
    $d = parent::__set_state($properties); // expects back a D, NOT a B
    $d->dprop = $properties['dprop'];
    return $d;
  }
}
$b = new B(10);
$v = var_export($b, TRUE);
eval('$z = ' . $v . ";");
var_dump($z);
$d = new D(20, 30);
$v = var_export($d, TRUE);
eval('$z = ' . $v . ";");
var_dump($z);

###Method __sleep

Syntax

  method-modifiers  function  __sleep  ( )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

The instance methods __sleep and __wakeup support serialization.

If a class has a __sleep method, the library function serialize calls that method to find out which visible instance properties it should serialize. (In the absence of a __sleep or serialize method, all instance properties are serialized, including ones defined in runtime). This information is returned by __sleep as an array of zero or more elements, where each element's value is distinct and is the name of a visible instance property. These properties' values are serialized in the order in which the elements are inserted in the array. If __sleep does not return a value explicitly, NULL is returned, and that value is serialized.

Besides creating the array of property names, __sleep can do whatever else might be needed before serialization occurs.

The alternative to using __sleep and __wakeup is implementing the Serializable interface.

Note that if a class defining __sleep and __wakeup is extended, and the derived class does not override the methods, the serialization and unserialization will be performed as if those were instances of the base class, e.g. additional properties may not be serialized or restored.

Examples

Consider a Point class that not only contains x- and y-coordinates, it also has an id property; that is, each distinct Point created during a program's execution has a unique numerical id. However, there is no need to include this when a Point is serialized. It can simply be recreated when that Point is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches).

class Point
{
  private static $nextId = 1;
  private $x;
  private $y;
  private $id;
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
    $this->id = self::$nextId++;  // assign the next available id
  }
  public function __sleep()
  {
    return array('y', 'x'); // serialize only $y and $x, in that order
  }
  public function __wakeup()
  {
    $this->id = self::$nextId++;  // assign a new id
  }
  ...
}
$p = new Point(-1, 0);
$s = serialize($p);   // serialize Point(-1,0)
$v = unserialize($s); // unserialize Point(-1,0)

###Method __toString

Syntax

  method-modifiers  function  __toString  ( )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

This function must return a string.

This function must not throw any exceptions.

Semantics

This instance method is intended to create a string representation of the instance on which it is called.

__toString is called by a number of language and library facilities, including echo, when an object-to-string conversion is needed. __toString can also be called directly.

An implementation of __toString should factor in the possibility of an instance having dynamic properties.

Examples

class Point
{
  private $x;
  private $y;
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
  }
  public function __toString()
  {
    return '(' . $this->x . ',' . $this->y . ')';
  }
  ...
}
$p1 = new Point(20, 30);
echo $p1 . "\n";  // implicit call to __toString() returns "(20,30)"
// -----------------------------------------
class MyRangeException extends Exception
{
  public function __toString()
  {
    return parent::__toString()
      . string-representation-of-MyRangeException
  }
  ...
}

###Method __unset

Syntax

  method-modifiers  function  __unset  (  $name  )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

If the dynamic property designated by $name exists, it is removed by this instance method; otherwise, the call has no effect. No value is expected to be returned.

Typically, __unset is called implicitly, when the intrinsic unset is called with an argument that designates a property that is not visible.

While __unset can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression unset($p->m), where p is an instance and m is a property name. If m is the name of a visible property, __unset is not called. Instead, the visible property is used. On the other hand, the expression p->__unset('m')) always removes the named dynamic property, ignoring the fact that a visible property having the same name might exist. If m is not the name of a visible property, the two expressions are equivalent; that is; when handling p->m in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed.

While the name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by $name. Any source character is allowed here.

Examples

class Point
{
    private $dynamicProperties = array();
    private $x;
    private $y;
    public function __unset($name)
    {
        unset($this->dynamicProperties[$name]);
    }
  ...
}

Implementation Notes

See the Implementation Notes for __get.

###Method __wakeup

Syntax

  method-modifiers  function  __wakeup  ( )  return-typeopt  compound-statement

Defined elsewhere

Constraints

The method-modifiers must not contain static and must define public visibility.

Semantics

The instance methods __sleep and __wakeup support serialization.

When the library function unserialize is called on the string representation of an object, as created by the library function serialize, unserialize creates an instance of that object's type without calling a constructor, and then calls that class's __wakeup method, if any, to initialize the instance. In the absence of a __wakeup method, all that is done is that the values of the instance properties encoded in the serialized string are restored.

__wakeup is not expected to return a value.

Consider a Point class that not only contains x- and y-coordinates, it also has an id property; that is, each distinct Point created during a program's execution has a unique numerical id. However, there is no need to include this when a Point is serialized. It can simply be recreated by __wakeup when that Point is unserialized. This means that __wakeup must emulate the constructor, as appropriate.

Examples

See __sleep.

##Serialization

In PHP, variables can be converted into some external form suitable for use in file storage or inter-program communication. The process of converting to this form is known as serialization while that of converting back again is known as unserialization. These facilities are provided by the library functions serialize and unserialize, respectively.

In the case of variables that are objects, on their own, these two functions serialize and unserialize all the instance properties, which may be sufficient for some applications. However, if the programmer wants to customize these processes, they can do so in one of two mutually exclusive ways. The first approach is to define methods called __sleep and __wakeup, and have them get control before serialization and after serialization, respectively. For information on this approach, see __sleep and __wakeup. The second approach involves implementing the interface Serializable by defining two methods, serialize and unserialize.

Consider a Point class that not only contains x- and y-coordinates, it also has an id property; that is, each distinct Point created during a program's execution has a unique numerical id. However, there is no need to include this when a Point is serialized. It can simply be recreated when that Point is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches). Furthermore, consider a class ColoredPoint that extends Point by adding a color property. The following code shows how these classes need be defined in order for both Points and ColoredPoints to be serialized and unserialized:

class Point implements Serializable // note the interface
{
  private static $nextId = 1;
  private $x;
  private $y;
  private $id;  // transient property; not serialized
  public function __construct($x = 0, $y = 0)
  {
    $this->x = $x;
    $this->y = $y;
    $this->id = self::$nextId++;
  }
  public function __toString()
  {
    return 'ID:' . $this->id . '(' . $this->x . ',' . $this->y . ')';
  }
  public function serialize()
  {
    return serialize(array('y' => $this->y, 'x' => $this->x));
  }

The custom method serialize calls the library function serialize to create a string version of the array, whose keys are the names of the instance properties to be serialized. The insertion order of the array is the order in which the properties are serialized in the resulting string. The array is returned.

  public function unserialize($data)
  {
    $data = unserialize($data);
    $this->x = $data['x'];
    $this->y = $data['y'];
    $this->id = self::$nextId++;
  }
}

The custom method unserialize converts the serialized string passed to it back into an array. Because a new object is being created, but without any constructor being called, the unserialize method must perform the tasks ordinarily done by a constructor. In this case, that involves assigning the new object a unique id.

$p = new Point(2, 5);
$s = serialize($p);

The call to the library function serialize calls the custom serialize method. Afterwards, the variable $s contains the serialized version of the Point(2,5), and that can be stored in a database or transmitted to a cooperating program. The program that reads or receives that serialized string can convert its contents back into the corresponding variable(s), as follows:

$v = unserialize($s);

The call to the library function unserialize calls the custom unserialize method. Afterwards, the variable $s contains a new Point(2,5).

class ColoredPoint extends Point implements Serializable
{
  const RED = 1;
  const BLUE = 2;

  private $color; // an instance property

  public function __construct($x = 0, $y = 0, $color = RED)
  {
    parent::__construct($x, $y);
    $this->color = $color;
  }

  public function __toString()
  {
    return parent::__toString() . $this->color;
  }

  public function serialize()
  {
    return serialize(array(
      'color' => $this->color,
      'baseData' => parent::serialize()
    ));
  }

As with class Point, this custom method returns an array of the instance properties that are to be serialized. However, in the case of the second element, an arbitrary key name is used, and its value is the serialized version of the base Point within the current ColoredPoint object. The order of the elements is up to the programmer.

    public function unserialize($data)
    {
    $data = unserialize($data);
    $this->color = $data['color'];
    parent::unserialize($data['baseData']);
    }
}

As ColoredPoint has a base class, it unserializes its own instance properties before calling the base class's custom method, so it can unserialize the Point properties.

$cp = new ColoredPoint(9, 8, ColoredPoint::BLUE);
$s = serialize($cp);
...
$v = unserialize($s);

Function unserialize takes an optional second argument, which specifies an array of trusted class names as strings. Objects found in the data stream whose type name is not in this trusted name list are converted to objects of type __PHP_Incomplete_Class.

Any attempt to serialize an object having an anonymous class type results in an instance of type Exception being thrown.

##Predefined Classes

Class Closure

The predefined class Closure is used for representing an anonymous function. It cannot be instantiated except by the Engine, as described below. Closure objects are immutable and must not permit the creation or modification of properties.

Closures can be bound, unbound or static. If a closure is said to be bound, then it has an object that $this will be bound to when called. If a closure is unbound, then it has no object $this will be bound to. If a closure is static, then it cannot be bound.

Closures can be scoped or unscoped. If a closure is said to be scoped, it has a class scope which determines the visibility of the private and protected members of objects of the class, including but not limited to such members on $this. If a closure is said to be unscoped, it has no class scope set.

Closures have an invariant that scoped closures must be bound or static, and unbound closures must be unscoped.

class Closure
{
  public static bind(Closure $closure, $newthis [, $newscope = "static" ]);
  public bindTo($newthis [, $newscope = "static" ]);
  public call($newthis [, ...$parameters ]);
}

The class members are defined below:

Name Purpose
bind Duplicates closure $closure with a specific bound object $newthis and class scope $newscope. If $newthis is NULL then the closure is to be unbound if no scope is specified, or static if a scope is specified. $newscope is the scope the closure is to be given (either a string containing the name of a class, or an object whose class will be used), or "static" to keep the current one. Returns a new Closure object or FALSE on failure. This function must not violate the invariant that closures must either be both scoped and bound or static, or otherwise both unscoped and unbound. This function must prevent binding an object to the new closure if the $closure is static, however the new closure may have a different scope.
bindTo Duplicates the closure designated by the current instance with a new-bound object and class scope. This method is an instance version of bind.
call Calls the closure (the current instance) with $this bound to $newthis, the class scope of the class of $newthis, and the parameters specified by $parameters. This function must fail if $newthis is NULL, or if the closure is static.

When the anonymous function creation operator is evaluated, the result is an object of type Closure (or some unspecified class derived from that type) created by the Engine. This object is referred to here as "the Closure object". This instance encapsulates the anonymous function defined in the corresponding anonymous-function-creation-expression.

The contents of a Closure object are determined based on the context in which an anonymous function is created. Consider the following scenario:

class C
{
  public function compute()
  {
    $count = 0;
    $values = array("red" => 3, 10);
    $callback = function ($p1, $p2) use (&$count, $values)
    {
      ...
    };
    ...
  }
}

A Closure object may contain the following, optional dynamic properties, in order: static, this, and parameter.

If an anonymous-function-creation-expression contains an anonymous-function-use-clause, a dynamic property called static is present. This is unrelated to whether a closure is said to be static. This property is an array having an element for each variable-name in the use-variable-name-list, inserted in lexical order of their appearance in the use clause. Each element's key is the corresponding variable-name, and each element value is the value of that variable at the time the time the Closure object is created (not when it is used to call the encapsulated function). In the scenario above, this leads to the following, shown as pseudo code:

$this->static = array(["count"]=>&0,["values"]=>array(["red"]=>3,[0]=>10));

If an anonymous-function-creation-expression is used inside an instance method, a dynamic property called this is present. This property is a handle that points to the current instance. In the scenario above, this leads to the following, shown as pseudo code:

$this->this = $this;

If an anonymous-function-creation-expression contains a parameter-declaration-list, a dynamic property called parameter is present. This property is an array of one or more elements, each of which corresponds to a parameter. The elements are inserted in that array in lexical order of their declaration. Each element's key is the corresponding parameter name, and each element value is some unspecified value. (These values are overridden by the argument values used when the anonymous function is called). In the scenario above, this leads to the following, shown as pseudo code:

$property = array("$p1" => ???, "$p2" => ???)

It is possible for all three dynamic properties to be absent, in which case, the Closure object is empty.

Closure objects can not be serialized or unserialized.

###Class Generator

This class supports the yield operator. This class cannot be instantiated directly. It is defined, as follows:

class Generator implements Iterator
{
  public function current();
  public function getReturn();
  public function key();
  public function next();
  public function rewind();
  public function send($value) ;
  public function throw(Exception $exception) ;
  public function valid();
}

The class members are defined below:

Name Purpose
current An implementation of the instance method Iterator::current.
getReturn Returns the final expression from a generator, which was produced by a return statement rather than a yield. This function can only be called meaningfully once the generator has finishing yielding values; otherwise, an instance of Exception is thrown.
key An implementation of the instance method Iterator::key.
next An implementation of the instance method Iterator::next.
rewind An implementation of the instance method Iterator::rewind.
send This instance method sends the value designated by $value to the generator as the result of the current yield expression, and resumes execution of the generator. $value is the return value of the yield expression the generator is currently at. If the generator is not at a yield expression when this method is called, it will first be let to advance to the first yield expression before sending the value. This method returns the yielded value.
throw This instance method throws an exception into the generator and resumes execution of the generator. The behavior is as if the current yield expression was replaced with throw $exception. If the generator is already closed when this method is invoked, the exception will be thrown in the caller's context instead. This method returns the yielded value.
valid An implementation of the instance method Iterator::valid.

Generator objects can not be serialized or unserialized.

###Class __PHP_Incomplete_Class

There are certain circumstances in which a program can generate an instance of this class, which on its own contains no members. One involves an attempt to unserialize a string that encodes an instance of a class for which there is no definition or if an objects type is declared untrusted by unserializes filter argument.

Consider the following code:

class Point
{
  private $x;
  private $y;
  ...
}
$p = new Point(2, 5);
$s = serialize($p); // properties $x and $y are serialized, in that order

Let us assume that the serialized string is stored in a database from where it is retrieved by a separate program. That program contains the following code, but does not contain a definition of the class Point:

$v = unserialize($s);

Instead of returning a point, Point(2, 5), an instance of __PHP_Incomplete_Class results, with the following contents:

__PHP_Incomplete_Class
{
   __PHP_Incomplete_Class_Name => "Point"
  x:Point:private => 2
  y:Point:private => 5
}

Object of this class can be serialized, however, any attemt to call its method or access its property for any other operation except serialization will result in a fatal error.

###Class stdClass

This class contains no members. It can be instantiated and used as a base class. An instance of this type is automatically created when a non-object is converted to an object, or the member selection operator is applied to NULL, FALSE, or an empty string.

###Predefined Error Classes

PHP has a number of predefined classes that are used for error reporting. All these classes extend the base Error class.

####Class Error

This class is the base class for all internal PHP error exceptions. It is defined, as follows:

class Error implements Throwable
{
  protected $message = '';
  protected $code = 0;
  protected $file;
  protected $line;

  public function __construct($message = "", $code = 0,
               Throwable $previous = NULL);

  final private function __clone();
}

Defined elsewhere

For information about the base interface, see Throwable. Note that the methods from Throwable are implemented as final in the Error class, which means the extending class can not override them.

####Class ArithmeticError

An instance of this class is thrown when an error occurs during certain mathematical operations. It is defined, as follows:

class ArithmeticError extends Error
{
}

Defined elsewhere

####Class AssertionError

An instance of this class is thrown when an assertion made via the intrinsic assert fails. The class type is defined, as follows:

class AssertionError extends Error
{
}

Defined elsewhere

####Class DivisionByZeroError

An instance of this class is thrown when an attempt is made to divide a number by zero, e.g. when using the remainder operators (% and %=). Note that this happens only for integer operations, regular float division (/) produces a non-fatal error instead. The class type is defined, as follows:

class DivisionByZeroError extends Error
{
}

Defined elsewhere

####Class ParseError

An instance of this class is thrown when an error occurs while parsing PHP code (such as when calling the intrinsic eval). It is defined, as follows:

class ParseError extends Error
{
}

Defined elsewhere

####Class TypeError

An instance of this class is thrown when any of the following occurs:

  • The type of an argument being passed to a function does not match its corresponding parameters declared type.
  • The type of the value being returned from a function does not match the functions declared return type.
  • In strict mode, an invalid number of arguments are passed to a library function.

The class is defined, as follows:

class TypeError extends Error
{
}

Defined elsewhere

See also class Exception.