Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

OOPS Concepts in PHP

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 40

Introduction

Starting with PHP 5, the object model was rewritten to allow for better performance and more features.
This was a major change from PHP 4. PHP 5 has a full object model.
Among the features in PHP 5 are the inclusions of visibility, abstract and final classes and methods,
additional magic methods, interfaces, cloning and typehinting.
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

• Classes and Objects


• Introduction
• The Basics
• Properties
• Class Constants
• Autoloading Classes
• Constructors and Destructors
• Visibility
• Object Inheritance
• Scope Resolution Operator (::)
• Static Keyword
• Class Abstraction
• Object Interfaces
• Overloading
• Object Iteration
• Patterns
• Magic Methods
• Final Keyword
• Object Cloning
• Comparing Objects
• Type Hinting
• Late Static Bindings
• Objects and references
• Object Serialization
Class
Every class definition begins with the keyword class, followed by a class name, followed by a pair of
curly braces which enclose the definitions of the class's properties and methods.
The class name can be any valid label which is a not a PHP reserved word. 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_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*.
A class may contain its own constants, variables (called "properties"), and functions (called
"methods").
<?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 a
reference to the calling object (usually the object to which the method belongs, but possibly another
object, if the method is called statically from the context of a secondary object).
<?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()
{
// Note: the next line will issue a warning if E_STRICT is en
abled.
A::foo();
}
}

$a = new A();
$a->foo();

// Note: the next line will issue a warning if E_STRICT is enabled.


A::foo();
$b = new B();
$b->bar();

// Note: the next line will issue a warning if E_STRICT is enabled.


B::bar();
?>

New
To create an instance of a class, a new object must be created and assigned to a variable. An object will
always be assigned when creating a new object 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).
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.
<?php
$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);
?>

Extends
A class can inherit the 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 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 as final, that method may
not be overridden. It is possible to access the overridden methods or static properties by referencing
them with parent::
<?php
class ExtendClass extends SimpleClass
{
// Redefine the parent method
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}

$extended = new ExtendClass();


$extended->displayVar();
?>
Properties
Class member variables are called "properties". You may also see them referred to using other terms
such as "attributes" or "fields", but for the purposes of this reference we will use "properties". They are
defined by using one of the keywords public, protected, or private, followed by a normal variable
declaration. This declaration may include an initialization, but this initialization must be a constant
value--that is, it must be able to be evaluated at compile time and must not depend on run-time
information in order to be evaluated.
See Visibility for more information on the meanings of public, protected, and private.
Note: In order to maintain backward compatibility with PHP 4, PHP 5 will still accept the
use of the keyword var in property declarations instead of (or in addition to) public,
protected, or private. However, var is no longer required. In versions of PHP from 5.0 to
5.1.3, the use of var was considered deprecated and would issue an E_STRICT warning,
but since PHP 5.1.3 it is no longer deprecated and does not issue the warning.
If you declare a property using var instead of one of public, protected, or private, then PHP
5 will treat the property as if it had been declared as public.

Within class methods the properties, constants, and methods may be accessed by using the form $this-
>property (where property is the name of the property) unless the access is to a static property within
the context of a static class method, in which case it is accessed using the form self::$property. See
Static Keyword for more information.
The pseudo-variable $this is available inside any class method when that method is called from within
an object context. $this is a reference to the calling object (usually the object to which the method
belongs, but possibly another object, if the method is called statically from the context of a secondary
object).
Class Constants
It is possible to define constant values on a per-class basis remaining the same and unchangeable.
Constants differ from normal variables in that you don't use the $ symbol to declare or use them.
The value must be a constant expression, not (for example) a variable, a property, a result of a
mathematical operation, or a function call.
Its also possible for interfaces to have constants. Look at the interface documentation for examples.
As of PHP 5.3.0, 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).
EXAMPLE := const constant = 'constant value';
<?php
class MyClass
{
const constant = 'constant value';

function showConstant() {
echo self::constant . "\n";
}
}

echo MyClass::constant . "\n";

$classname = "MyClass";
echo $classname::constant . "\n"; // As of PHP 5.3.0

$class = new MyClass();


$class->showConstant();

echo $class::constant."\n"; // As of PHP 5.3.0


?>
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).
In PHP 5, this is no longer necessary. You may define an __autoload function which is automatically
called in case you are trying to use a class/interface which hasn't been defined yet. By calling this
function the scripting engine is given a last chance to load the class before PHP fails with an error.
Note: Exceptions thrown in __autoload function cannot be caught in the catch block and
results in a fatal error.

Note: Autoloading is not available if using PHP in CLI interactive mode.

Note: If the class name is used e.g. in call_user_func() then it can contain some dangerous
characters such as ../. It is recommended to not use the user-input in such functions or at
least verify the input in __autoload().

?php
function __autoload($class_name) {
require_once $class_name . '.php';
}

$obj = new MyClass1();


$obj2 = new MyClass2();
?>
Constructors and Destructors
Constructor
void __construct ([ mixed $args [, $... ]] )
PHP 5 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.

<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}

class SubClass extends BaseClass {


function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}

$obj = new BaseClass();


$obj = new SubClass();
?>

For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will
search for the old-style constructor function, by the name of the class. Effectively, it means that the
only case that would have compatibility issues is if the class had a method named __construct() which
was used for different semantics.

Destructor
void __destruct ( void )
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++.
The destructor method will be called as soon as all references to a particular object are removed or
when the object is explicitly destroyed or in any order in shutdown sequence.
<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "Destroying " . $this->name . "\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.
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.
Visibility
The visibility of a property or method 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 inherited and parent classes.
Members declared as private may only be accessed by the class that defines the member.

Property Visibility
Class properties must be defined as public, private, or protected. If declared using var without an
explicit visibility keyword, the property will be defined as public.
Note: The PHP 4 method of declaring a variable with the var keyword is still supported for
compatibility reasons (as a synonym for the public keyword). In PHP 5 before 5.1.3, its
usage would generate an E_STRICT warning.
<?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 method, but not
private
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}

$obj2 = new MyClass2();


echo $obj2->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello(); // Shows Public, Protected2, Undefined

?>
Method Visibility
Class methods may be defined as public, private, or protected. Methods declared without any
explicit visibility keyword are defined as public.
<?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
?>
Object Inheritance
Inheritance is a well-esablished 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 you extend a class, the subclass inherits all of the public and protected methods
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.
<?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'

?>
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 static, constant, and overridden properties or methods of a class.
When referencing these items from outside the class definition, use the name of the class.
As of PHP 5.3.0, 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!
<?php
class MyClass {
const CONST_VALUE = 'A constant value';
}

$classname = 'MyClass';
echo $classname::CONST_VALUE; // As of PHP 5.3.0

echo MyClass::CONST_VALUE;
?>
<?php
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';
echo $classname::doubleColon(); // As of PHP 5.3.0

OtherClass::doubleColon();
?>
When an extending class overrides the parents definition of a method, PHP will not call the parent's
method. It's up to the extended class on whether or not the parent's method is called. This also applies
to Constructors and Destructors, Overloading, and Magic method definitions.
Static Keyword
Declaring class properties or methods as static makes them accessible without needing an instantiation
of the class. A property declared as static can not be accessed with an instantiated class object (though a
static method can).
For compatibility with PHP 4, if no visibility declaration is used, then the property or method will be
treated as if it was declared as public.
Because static methods are callable without an instance of the object created, the pseudo-variable $this
is not available inside the method declared as static.
Static properties cannot be accessed through the object using the arrow operator ->.
Calling non-static methods statically generates an E_STRICT level warning.
Like any other PHP static variable, static properties may only be initialized using a literal or constant;
expressions are not allowed. So while you may initialize a static property to an integer or array (for
instance), you may not initialize it to another variable, to a function return value, or to an object.
As of PHP 5.3.0, 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).
<?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"; // As of PHP 5.3.0

print Bar::$my_static . "\n";


$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
Class Abstraction

PHP 5 introduces abstract classes and methods. It is not allowed to create an instance of a class that has
been defined as abstract. Any class that contains at least one abstract method must also be abstract.
Methods defined as abstract simply declare the method's signature they cannot define the
implementation.
When inheriting from an abstract class, all methods marked abstract in the parent's class declaration
must be defined by the child; additionally, these methods must be defined with the same (or a less
restricted) visibility. For example, if the abstract method is defined as protected, the function
implementation must be defined as either protected or public, but not private.
<?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";
?>
Object Interfaces
Object interfaces allow you to create code which specifies which methods a class must implement,
without having to define how these methods are handled.
Interfaces are defined using the interface keyword, in the same way as a standard class, but 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.

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.
Note: A class cannot implement two interfaces that share function names, since it would
cause ambiguity.

Note: Interfaces can be extended like classes using the extend operator.

Note: The class implementing the interface must use the exact same method signatures as
are defined in the interface. Not doing so will result in a fatal error.

Constants
Its possible for interfaces to have constants. Interface constants works exactly like class constants. They
cannot be overridden by a class/interface that inherits it.

Examples
<?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)


{
}
}
?>
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.

Changelog
Version Description
5.3.0 Added __callStatic(). Added warning to enforce public visibility and non-static declaration.
5.1.0 Added __isset() and __unset().

Property overloading
void __set ( string $name , mixed $value )
mixed __get ( string $name )
bool __isset ( string $name )
void __unset ( string $name )
__set() is run when writing data to inaccessible properties.
__get() is utilized for reading data from inaccessible properties.
__isset() is triggered by calling isset() or empty() on inaccessible properties.
__unset() is invoked when unset() is used on inaccessible 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 can not be 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 assignemnts together
like this:

$a = $obj->b = 8;

<?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 clas
s. */
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;
}

/** As of PHP 5.1.0 */


public function __isset($name) {
echo "Is '$name' set?\n";
return isset($this->data[$name]);
}

/** As of PHP 5.1.0 */


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;
}
}

echo "<pre>\n";
$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";
?>
Method overloading
mixed __call ( string $name , array $arguments )
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.
<?php
class MethodTest {
public function __call($name, $arguments) {
// Note: value of $name is case sensitive.
echo "Calling object method '$name' "
. implode(', ', $arguments). "\n";
}

/** As of PHP 5.3.0 */


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'); // As of PHP 5.3.0
?>
Object Iteration
PHP 5 provides a way for objects to be defined so it is possible to iterate through a list of items, with,
for example a foreach statement. By default, all visible properties will be used for the 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();

?>
Patterns
Patterns are ways to describe best practices and good designs. They show a flexible solution to
common programming problems.

Factory
The Factory pattern allows for the instantiation of objects at runtime. It is called a Factory Pattern since
it is responsible for "manufacturing" an object. A Parameterized Factory receives the name of the class
to instantiate as argument.

<?php
class Example
{
// The parameterized factory method
public static function factory($type)
{
if (include_once 'Drivers/' . $type . '.php') {
$classname = 'Driver_' . $type;
return new $classname;
} else {
throw new Exception ('Driver not found');
}
}
}
?>
Singleton
The Singleton pattern applies to situations in which there needs to be a single instance of a class. The
most common example of this is a database connection. Implementing this pattern allows a
programmer to make this single instance easily accessible by many other objects.
<?php
class Example
{
// Hold an instance of the class
private static $instance;

// A private constructor; prevents direct creation of object


private function __construct()
{
echo 'I am constructed';
}

// The singleton method


public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}

return self::$instance;
}

// Example method
public function bark()
{
echo 'Woof!';
}

// Prevent users to clone the instance


public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}

?>
Magic Methods
The function names __construct, __destruct, __call, __callStatic, __get, __set, __isset, __unset,
__sleep, __wakeup, __toString, __invoke, __set_state and __clone are magical in PHP classes. You
cannot have functions with these names in any of your classes unless you want the magic functionality
associated with them.
Caution
PHP reserves all function names starting with __ as magical. It is recommended that you do not use
function names with __ in PHP unless you want some documented magic functionality.

__sleep and __wakeup


serialize() checks if your 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
NULL is serialized and E_NOTICE is issued.
The intended use of __sleep is to commit pending data or perform similar cleanup tasks. Also, the
function is useful if you have very large objects which do not 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.
__toString
The __toString method allows a class to decide how it will react when it is converted to a string.
It is worth noting that before PHP 5.2.0 the __toString method was only called when it was directly
combined with echo() or print(). Since PHP 5.2.0, it is called in any string context (e.g. in printf() with
%s modifier) but not in other types contexts (e.g. with %d modifier). Since PHP 5.2.0, converting
objects without __toString method to string would cause E_RECOVERABLE_ERROR.

__invoke
The __invoke method is called when a script tries to call an object as a function.
__set_state
This static method is called for classes exported by var_export() since PHP 5.1.0.
The only parameter of this method is an array containing exported properties in the form
array('property' => value, ...).
Final Keyword
PHP 5 introduces the final keyword, which prevents child classes from overriding a method by
prefixing the definition with final. If the class itself is being defined final then it cannot be extended.
<?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::mo
reTesting()
?>
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). An object's __clone() method cannot be called directly.

$copy_of_object = clone $object;

When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. Any
properties that are references to other variables, will remain references.
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 that need to be changed.
<?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);

?>
Comparing Objects
In PHP 5, object comparison is more complicated than in PHP 4 and more in accordance to what one
will expect from an Object Oriented Language (not that PHP 5 is such a language).
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, and are instances of the
same class.
On the other hand, 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.
<?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 Flag($flag = true) {


$this->flag = $flag;
}
}

class OtherFlag
{
public $flag;

function OtherFlag($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);
?>
Type Hinting
PHP 5 introduces Type Hinting. Functions are now able to force parameters to be objects (by
specifying the name of the class in the function prototype) or arrays (since PHP 5.1). However, if
NULL is used as the default parameter value, it will be allowed as an argument for any later call.
<?php
// An example class
class MyClass
{
/**
* A test function
*
* First parameter must be an object of type OtherClass
*/
public function test(OtherClass $otherclass) {
echo $otherclass->var;
}

/**
* Another test function
*
* First parameter must be an array
*/
public function test_array(array $input_array) {
print_r($input_array);
}
}

// Another example class


class OtherClass {
public $var = 'Hello World';
}
?>
Late Static Bindings
As of PHP 5.3.0, PHP implements a feature called late static bindings which can be used to reference
the called class in a context of static inheritance.
This feature was named "late static bindings" with an internal perspective in mind. "Late binding"
comes from the fact that static:: will no longer 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:
<?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();
?>

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 you to reference B from test() in
the previous example. It was decided not to introduce a new keyword but rather use static that was
already reserved.
<?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();
?>

Edge cases
There are lots of different ways to trigger a method call in PHP, like callbacks or magic methods. As
late static bindings base their resolution on runtime information, it might give unexpected results in so-
called edge cases.
<?php
class A {

protected static function who() {


echo __CLASS__."\n";
}

public function __get($var) {


return static::who();
}
}

class B extends A {

protected static function who() {


echo __CLASS__."\n";
}
}

$b = new B;
$b->foo;
?>
Objects and references
One of the key-points of PHP5 OOP that is often mentioned is that "objects are passed by references 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. As of
PHP5, an object variable doesn't contain the object itself as value anymore. 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.
<?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";

?>
Object Serialization

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 variabled contained it. If you want to be able to unserialize this in another file, an object of
class A, the definition of class A must be prest ent in 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
// classa.inc:

class A {
public $one = 1;

public function show_one() {


echo $this->one;
}
}

// page1.php:

include("classa.inc");

$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("classa.inc");

$s = file_get_contents('store');
$a = unserialize($s);

// now use the function show_one() of the $a object.


$a->show_one();
?>
If an application is using sessions and uses session_register() to register objects, these objects are
serialized automatically at the end of each PHP page, and are unserialized automatically on each of the
following pages. This means that these objects can show up on any of the application's pages once they
become part of the session. However, session_register() is deprecated as of PHP 5.3.0, and removed as
of PHP 6.0.0. Reliance on this function is not recommended.
It is strongly recommended that if an application serializes objects, for use later in the application, that
the application include 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 running session_register("a"), you should
include the file classa.inc on all of your pages, not only page1.php and page2.php.

You might also like