I shall assume that you are familiar with Object-oriented Programming (OOP) concepts and terminologies. Otherwise, read "Java OOP" or "C++ OOP".
Getting started by Examples
Let's get started with examples on:
- Defining a class with private member variables, constructor, destructor, public getters/setters and public methods;
- Allocating instances instances of the class;
- Accessing instance's variable/functions.
Example: MyCircle Class
We shall begin with a class called MyCircle
, which models a circle with a specific radius, as shown in the following class diagram.
MyCircle.php
The definition of the MyCircle
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php // MyCircle.php /** * The MyCircle class models a Circle with a specific radius. */ class MyCircle { // private variable private $radius; // radius of the circle /** * Constructor to allocate an instance and initialize its private variables. * @param number $radius: radius of the circle, with default value of 1 */ public function __construct($radius = 1) { $this->radius = $radius; // "$this" refers to the current instance. echo 'Constructed an instance of ', __CLASS__, ' with radius=', $this->radius, ".\n"; // "__CLASS__" is a special magic constant that stores the class name. } /** * Destructor - invoked just before the instance is deallocated. */ public function __destruct() { echo 'Destructed instance ', $this, ' of ', __CLASS__, ".\n"; } /** * Getter for radius. * @return number: radius of the circle. */ public function getRadius() { return $this->radius; } // You cannot omit $this-> (unlike Java). /** * Setter for radius. * @param number $radius: radius of the circle. */ public function setRadius($radius) { $this->radius = $radius; } /** * Return a string representation of this instance. * @return string: in the form of 'MyCircle[radius=r]'. */ public function __toString() { return __CLASS__ . '[radius=' . $this->radius . ']'; } /** * Return the area of this circle. * @return number: area of the circle. */ public function getArea() { return $this->radius * $this->radius * pi(); } } |
MyCircleTest.php
A test driver for the MyCircle
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php // MyCircleTest.php require_once 'MyCircle.php'; // Allocate an instance of class MyCircle $c1 = new MyCircle(1.1); // Test constructor // Try different ways of printing an object var_dump($c1); print_r($c1); var_export($c1); echo "\n"; echo "Radius is: {$c1->getRadius()}\n"; // Test getter $c1->setRadius(5); // Test setter echo "$c1\n"; // Call __toString() implicitly echo "{$c1->getArea()}\n"; // Test getArea() $c2 = new MyCircle(); // Test constructor with default argument echo "$c2\n"; echo "Done.\n"; // Run the destructor before deallocating the instances at end of file. ?> |
You can run the program via the PHP CLI (Command-Line Interface):
$ php MyCircleTest.php
The expected outputs are:
Constructed an instance of MyCircle with radius=1.1. object(MyCircle)#1 (1) { // var_dump() ["radius":"MyCircle":private]=> float(1.1) } MyCircle Object // print_r() (for human-readable output) ( [radius:MyCircle:private] => 1.1 ) MyCircle::__set_state(array( // var_export(), which can be re-imported in a PHP program 'radius' => 1.1000000000000001, )) Radius is: 1.1 MyCircle[radius=5] 78.539816339745 Constructed an instance of MyCircle with radius=1. MyCircle[radius=1] Done. Destructed instance MyCircle[radius=1] of MyCircle. Destructed instance MyCircle[radius=5] of MyCircle.
Example: MyTime Class
The MyTime
class models a time instance of hour, minute and second, as shown in the following class diagram.
MyTime.php
The class definition for the MyTime
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
<?php // MyTime.php /** * MyTime class models an instance of time. */ class MyTime { // private properties private $hour, $minute, $second; /** * Constructor to allocate a new instance and initialize all private variables. * @param int $hour: hour in 0-23 * @param int $minute: minute in 0-59 * @param int $second: second in 0-59 */ public function __construct($hour = 0, $minute = 0, $second = 0) { $this->setTime($hour, $minute, $second); echo 'Constructed an instance of ', __CLASS__, ' with value ', $this, ".\n"; // "__CLASS__" is a special magic constant that stores the class name. // "$this" refers to the current instance. } /** * Destructor - invoked just before the instance is deallocated. */ public function __destruct() { echo 'Destructed instance ', $this, ' of ', __CLASS__, ".\n"; } /** * Getter for hour * @return int hour */ public function getHour() { return $this->hour; } // You cannot omit $this-> (unlike Java). /** * Getter for minute * @return int minute */ public function getMinute() { return $this->minute; } /** * Getter for second * @return int second */ public function getSecond() { return $this->second; } /** * Setter for hour * @param int $hour: hour in 0-23 */ public function setHour($hour) { if ($hour < 0 or $hour > 23) { throw new InvalidArgumentException("Invalid hour $hour. Hour shall be 0-23.\n"); } $this->hour = $hour; } /** * Setter for minute * @param int $minute: minute in 0-59 */ public function setMinute($minute) { if ($minute < 0 or $minute > 59) { throw new InvalidArgumentException("Invalid minute $minute. Minute shall be 0-59.\n"); } $this->minute = $minute; } /** * Setter for second * @param int $second: second in 0-59 */ public function setSecond($second) { if ($second < 0 or $second > 59) { throw new InvalidArgumentException("Invalid second $second. Second shall be 0-59.\n"); } $this->second = $second; } /** * Set the hour, minute and second. * @param int $hour: hour in 0-23 * @param int $minute: minute in 0-59 * @param int $second: second in 0-59 */ public function setTime($hour = 0, $minute = 0, $second = 0) { $this->setHour($hour); $this->setMinute($minute); $this->setSecond($second); } /** * Return a string representation of this instance. * @return string: in the form of "HH:MM:SS". */ public function __toString() { return sprintf("%02d:%02d:%02d", $this->hour, $this->minute, $this->second); } /** * Increment one second. * @return MyTime $this to support chain operations. */ public function nextSecond() { ++$this->second; if ($this->second > 59) { $this->second = 0; ++$this->minute; } if ($this->minute > 59) { $this->minute = 0; ++$this->hour; } if ($this->hour > 23) { $this->hour = 0; } return $this; } } ?> |
MyTimeTest.php
A test driver for the MyTime
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<?php // MyTimeTest.php require_once 'MyTime.php'; // Allocate an instance of class MyTime $t1 = new MyTime(23, 59, 59); // Call constructor // Try different ways of printing an object var_dump($t1); print_r($t1); var_export($t1); echo "\n"; echo "Hour is: {$t1->getHour()}\n"; // Call getter $t1->setHour(12); // Call setter echo "$t1\n"; // Call __toString() implicitly // Increment 3 second and invoke __toString() echo $t1->nextSecond()->nextSecond()->nextSecond(), "\n"; // Allocate more instances $t2 = new MyTime(12, 34); // default second echo "$t2\n"; $t3 = new MyTime; // default hour, minute and second echo "$t3\n"; // Exception handling with try-catch try { $t4 = new MyTime(25); echo "This statement would not run, if an exception was thrown."; } catch (InvalidArgumentException $e) { echo 'Caught InvalidArgumentException: ', $e->getMessage(), "\n"; } echo "Done.\n"; // Run the destructor before deallocating the instances at end of file. ?> |
The output is:
Constructed an instance of MyTime with value 23:59:59. object(MyTime)#1 (3) { //var_dump() ["hour":"MyTime":private]=> int(23) ["minute":"MyTime":private]=> int(59) ["second":"MyTime":private]=> int(59) } MyTime Object //print_r() ( [hour:MyTime:private] => 23 [minute:MyTime:private] => 59 [second:MyTime:private] => 59 ) MyTime::__set_state(array( //var_export() - in a format can be used imported 'hour' => 23, 'minute' => 59, 'second' => 59, )) Hour is: 23 12:59:59 13:00:02 Constructed an instance of MyTime with value 12:34:00. 12:34:00 Constructed an instance of MyTime with value 00:00:00. 00:00:00 Caught InvalidArgumentException: Invalid hour 25. Hour shall be 0-23. Done. Destructed instance 00:00:00 of MyTime. Destructed instance 12:34:00 of MyTime. Destructed instance 13:00:02 of MyTime.
How OOP works in OOP
Defining a Class
A class consists of member variables and functions. To define a class, use keyword class
, as follows:
class { memberVariables; memberFunctions; }
Constructor __construct()
Constructor is a special function called __construct()
. Constructor is used to construct an instance and initialize the instance variables. To construct an instance of a class, you need to invoke the constructor via the new
operator (as illustrated in the test driver). Constructor does not return anything, hence, there shall not be a return
statement inside a constructor.
public function __construct( arguments ) { body; }
PHP does NOT support function overloading (unlike C++ and Java). In other words, there is only one version of the constructor. However, in PHP, you can provide default value to function parameters, including constructors. In this way, the constructor can be invoked with different set of arguments. For example,
// Constructor of MyTime class public function __construct($hour = 0, $minute = 0, $second = 0) { ...... } // Invoke the constructor $t1 = new MyTime(23, 59, 59); $t2 = new MyTime(23, 59); // default second $t3 = new MyTime(23); // default minute and second $t3 = new MyTime; // default hour, minute and second
PHP does not provide a default no-arg (no-argument) constructor (unlike Java). You need to explicitly define the constructor, if required.
Destructor __destruct()
Similarly, you can define a destructor called __destruct()
for a class. Destructor shall not carry any parameter. It will be run before the instance is destructed (or deallocated). Destructors are not commonly-used.
From the outputs of the above examples, it can be seen that the destructor is called on all objects when end-of-file is reached, before the program exits. To explicitly trigger the destructor, you can invoke unset()
on an object. For example,
$t1 = new MyTime;
unset($t1); // Invoke destructor
Allocating an Instance - the new Operator
To allocate an instance of a class, use the new
operator to invoke a constructor, in the form of new ClassName(parameters)
.
// Examples $t1 = new MyTime(23, 59, 59); $t2 = new MyTime; // using default value for arguments
Accessing Members - the Member-of Operator (->)
To access member variables/functions, use member-of operator (->
), in the form of $instanceName->memberName
. For example,
$t1 = new MyTime(23, 59, 59); echo $t1->getHour(); // Invoke getter $t1->setHour(12); // Invoke setter
$this
$this
refers to the current instance. To reference a member variable/function WITHIN the class definition, you MUST precede with $this
, e.g., $this->hour
, $this->getHour()
. Take note that you cannot omit $this
(unlike Java).
Access Control Modifiers - public, private and protected
We can use access control modifier to restrict access to a member variable/function. PHP supports these access control modifiers for member variables and functions:
- public: Accessible by all. This is the default.
- private: Accessible within the class only.
- protected: Accessible by subclasses.
Getters and Setters
Getters are setters are used to access and mutate private member variables, as shown in the above examples.
It is a common PHP practice to use the same function for getter cum setter, differentiated by its argument. For example,
// Getter cum Setter public function hour ($hour = NULL) { if ($hour !== NULL) { $this->hour = $hour; } return $this->hour; } // Test echo $t1->hour(), "\n"; // Getter echo $t1->hour(18), "\n"; // Setter
__toString()
__toString()
is one of the so-called magic methods, which shall return a string representation of the current instance. It is implicitly invoked when the object is to be treated as a string. For example,
$t1 = new MyTime(12, 34, 56);
echo $t1; // Invoke __toString() implicitly.
Take note that if __toString()
is not defined, "echo $t1
" will cause a runtime error.
__toString()
is similar to toString()
in Java. However, unlike Java classes which always inherit a toString()
from the root superclass java.lang.Object
, __toString()
in PHP must be explicitly defined for each class.
__CLASS__
__CLASS__
is one of the so-called magic constants in PHP, which keeps the class name in string.
DocBlock (or PhpDoc) Comment
Comments enclosed with /** .... */
are known as "DocBlock" or "PhpDoc", which can be extracted to produce documentation (like JavaDoc). You can use markups like params
and return
to target the descriptions.
Exception Handling and try-catch-finally
The statements in the try block are executed in sequence. If one of the statements throws an exception, the rest of the statements will not be executed. Instead, execution switches to the catch block. If all the statements in try block do not throw any exception, then try block completes, and catch block is not executed. Take note that execution always resumes after the try-catch block, regardless of whether there is any exception.
The try-catch construct supports graceful handling of errors/exception. Without try-catch, the program will be abruptly terminated when an exception is encountered. The try-catch construct also segregates the main logic and the exception handling logic, for better software engineering.
More OOP
static
A static
member (variable or function) belongs to the class, not to the instances. In other words, all the instances share the same copy of a static member.
For example, let rewrite our MyCircle class to include a static
variable $count
to maintain the count of circles created, as shown in the following class diagram. Note that static members are underlined in the UML notation.
MyCircleWithCount.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<?php // MyCircleWithCount.php /** * The MyCircleWithCount class models a Circle with a specific radius. * It also maintains the number of circle instances created, via a static variable. */ class MyCircleWithCount { // static variable private static $count = 0; // count of instances // private variable private $radius; // radius of the circle /** * Constructor to allocate an instance and initialize its private variables. * @param number $radius: radius of the circle, with default value of 1 */ public function __construct($radius = 1) { $this->radius = $radius; echo 'Constructed a ', __CLASS__, '. Number of circles is: ', ++self::$count, ".\n"; // You MUST use :: (scope resolution operator) instead of -> (member-of operator) to // access static members. // Within class definition, SELF refers to this class. // Pre-increment $count before echo. } /** * Destructor - invoked just before the instance is deallocated. */ public function __destruct() { echo 'Destructed a ', __CLASS__, '. Number of circles is: ', --self::$count, ".\n"; } public function getRadius() { return $this->radius; } public function setRadius($radius) { $this->radius = $radius; } public function __toString() { return __CLASS__ . '[radius=' . $this->radius . ']'; } public function getArea() { return $this->radius * $this->radius * pi(); } } ?> |
MyCircleWithCountTest.php
1 2 3 4 5 6 7 8 9 10 11 |
<?php // MyCircleWithCountTest.php require_once 'MyCircleWithCount.php'; $c1 = new MyCircleWithCount(1.1); $c2 = new MyCircleWithCount(2.2); unset($c2); // deallocate - run the destructor $c3 = new MyCircleWithCount(3.3); echo 'Number of circles is: ', MyCircleWithCount::$count, "\n."; // You can access public static variables via ClassName::memberName echo "Done.\n"; ?> |
The expected outputs are:
Constructed a MyCircleWithCount. Number of circles is: 1. Constructed a MyCircleWithCount. Number of circles is: 2. Destructed a MyCircleWithCount. Number of circles is: 1. Constructed a MyCircleWithCount. Number of circles is: 2. Number of circles is: 2 Done. Destructed a MyCircleWithCount. Number of circles is: 1. Destructed a MyCircleWithCount. Number of circles is: 0.
Can you do the count without static
?
Constants - const
A constant member variable is identified by keyword const
. Constants are always public
and static
, their content cannot be modified. Unlike normal variables, constants do not begin with a leading $ sign. Within the class definition, constants can be referenced via self::constantName
, just like any static
member. Outside the class definition, they are referenced via className::constantName
. By convention, use uppercase for constant names, e.g., ERROR_CODE
, ERROR_MESSAGE
.
Magic Methods and Constants
Magic methods are special methods, beginning with double underscore, that can be defined in any class and are executed via the built-in PHP functionality. For examples,
__construct()
: constructor.__destruct()
: destructor.__toString()
: returns a string representation of this object. Called implicitly if a string is expected.__clone()
: for cloning a copy.__sleep()
and__wakeup()
: for serialization.__unset()
,__isset()
,__get()
and__set()
: Called when trying to access a member variable which is not available.__unset()
is triggered byunset()
;__isset()
is triggered byisset()
.__call()
and__callStatic()
: Called when trying to call a function (or static function) which is not available.__set_state()
: viavar_export()
.__invoke()
:
[TODO] Examples
Magic constants (public
and static
), named in uppercase and beginning and ending with double underscore (without a leading $), contains special read-only properties. For examples,
__CLASS__
: the current classname in string.__FILE__
: the current filename.__LINE__
: the line number, used in conjunction with__FILE__
.__DIR__
: absolute directory, same asdir(__FILE__)
.__FUNCTION__
and__METHOD__
: the function or method name.__NAMESPACE__
: the current namespace in string.
[TODO] Examples
self::, parent:: and static::
self::
, parent::
and static::
allow you to access static
members and const
(public
and static
) WITHIN the class definition. self::
refer to the current class, as illustrated in the above example. parent::
refer to the superclass and static::
refer to the current class but with late binding - which will be discussed later in inheritance.
Recall that outside the class definition, you could access public
static
member and const
via ClassName::memberName
.
self vs. $this
Use $this
to refer to the current object. Use self
to refer to the current class. In other words, within a class definition, use $this->member
to reference non-static
members, use self::$member
for static
members.
Type Hinting for Function Parameters
In function definition, you can declare the TYPE of the parameters, such as array
, a class or interface name, or callable
. However, type hinting are NOT applicable for scalar types, such as int or string. For example,
function fun (array $a, Circle $b, $c) { ...... } // $a is an array; $b is an object of class Circle; $c unknown
Inheritance
Example: MyCircle and MyCylinder classes
Let's illustrate superclass-subclass inheritance with the following example of MyCircle
and MyCylinder
classes.
MyCircle.php
Same as the previous example.
MyCylinder.php
The MyCylinder
class inherits from the MyCircle
class, with more member variables/functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?php // MyCylinder.php require_once 'MyCircle.php'; /** * The MyCylinder class models a cylinder with base radius and height. * It inherits from the MyCircle class. */ class MyCylinder extends MyCircle { // keyword "extends" denotes inheritance // private variable private $height; // height of the cylinder /** * Constructor to allocate an instance and initialize its private variables. * @param number $radius: radius of the base circle, with default value of 1 * @param number $height: height of the cylinder, with default value of 1 */ public function __construct($radius = 1, $height = 1) { parent::__construct($radius); // Invoke the MyCircle's constructor to construct the base circle $this->height = $height; echo 'Constructed an instance of ', __CLASS__, ': ', self::__toString(), "\n."; } // Destructor public function __destruct() { echo 'Destructed instance of ', self::__toString(), "\n."; } // Getter and Setter public function getHeight() { return $this->height; } public function setHeight($height) { $this->height = $height; } // Return a string representation of this instance. public function __toString() { return __CLASS__ . '[height=' . $this->height . ', ' . parent::__toString() . ']'; } // Public method public function getVolume() { return $this->getArea() * $this->height; // $this->getArea() invoke superclass method } } ?> |
MyCylinderTest.php
A test driver for the MyCylinder
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php // MyCylinderTest.php require_once 'MyCylinder.php'; // Allocate an instance of subclass MyCylinder. $cy1 = new MyCylinder(5.6, 7.8); print_r($cy1); echo "$cy1\n"; // __toString() echo "Radius is: {$cy1->getRadius()}\n"; // Call superclass function echo "Base area is: {$cy1->getArea()}\n"; // Call superclass function echo "Volume is: {$cy1->getVolume()}\n"; // Call subclass function $cy1->setHeight(9.9); echo "New height is: {$cy1->getHeight()}\n"; echo "Done.\n" ?> |
The expected outputs are:
Constructed an instance of MyCircle with radius=5.6. Constructed an instance of MyCylinder: MyCylinder[height=7.8, MyCircle[radius=5.6]] .MyCylinder Object ( [height:MyCylinder:private] => 7.8 [radius:MyCircle:private] => 5.6 ) MyCylinder[height=7.8, MyCircle[radius=5.6]] Radius is: 5.6 Base area is: 98.520345616576 Volume is: 768.45869580929 New height is: 9.9 Done. Destructed instance of MyCylinder[height=9.9, MyCircle[radius=5.6]]
How Inheritance works
extends
You can define a subclass inheriting a superclass via keyword extends
.
self and parent
Within the subclass definition, you can use the keyword parent
in the form of parent::memberName
to refer to a member of the superclass; and self
in the form of self::memberName
to refer to a member of the subclass. The ::
is known as scope resolution operator.
Method Overriding
The subclass can override the inherited method from the superclass by providing its own definition. For example, the MyCylinder
class can override the getArea()
method inherited from superclass MyCircle
as follows:
class MyCylinder extends MyCircle { ...... ...... // Override inherited superclass' getArea() to return the surface area public function getArea() { return 2 * pi() * parent::getRadius() * $this->height; // Cannot use parent::$radius as it is private, not public nor protected } // Need to rewrite to invoke superclass' getArea() public function getVolume() { return parent::getArea() * $this->height; } } $c1 = new MyCircle(1.0); echo "Area is: {$c1->getArea()}\n"; $cy1 = new MyCylinder(2.0); echo "Surface area is: {$cy1->getArea()}\n";
final
A final
variable/method cannot be overridden in the subclass.
Polymorphism
abstract method and abstract class
An abstract
method is a method with only the signature, without implementation. A class containing one or more abstract
methods is an abstract
class. An abstract
class cannot be instantiated, as it's definition is incomplete. To use an abstract
class, derive a subclass and override the abstract
methods. The subclass is now complete and can be instantiated.
For example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php // TestAbstractClass.php // The MyShape class contains an abstract method called getArea(); // Hence, the MyShape class must be declared abstract abstract class MyShape { abstract public function getArea(); // An abstract method only have signature, without implementation body } // The MyRectangle class extends MyShape, and overrides the getArea() // to provide its implementation. // The MyRectangle class is concrete, and can be instantiated. class MyRectangle extends MyShape { private $width, $length; // Constructor public function __construct($width, $length) { $this->width = $width; $this->length = $length; } // Override public function getArea() { return $this->width * $this->length; } } // Test $r = new MyRectangle(3, 4); // Can create instance of concrete class echo "Area is: {$r->getArea()}\n"; $a = new MyShape(); // error: Cannot instantiate abstract class MyShape |
Interface
An interface is a pure abstract
class, which contains only abstract
methods. An interface is defined using keyword interface
(instead of class
). To derive a subclass from an interface, use keyword implements
(instead of extends
).
For examples,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php // TestInterface.php // Define an interface called MyShape which contains only abstract methods. interface MyShape { public function getArea(); public function getPerimeter(); // No need to include the abstract keyword } // The MyRectangle class implements MyShape, and overrides all the abstract methods class MyRectangle implements MyShape { private $width, $length; // Constructor public function __construct($width, $length) { $this->width = $width; $this->length = $length; } // Override public function getArea() { return $this->width * $this->length; } public function getPerimeter() { return 2 * ($this->width + $this->length); } } // Test $r = new MyRectangle(3, 4); // Can create instance of concrete class echo "Area is: {$r->getArea()}\n"; echo "Perimeter is: {$r->getPerimeter()}\n"; $s = new MyShape(); // error: Cannot instantiate interface MyShape |
Take note that PHP's implementations of abstract class and interface are exactly the same as Java.
trait
See:
- "Using Traits in PHP 5.4" @ http://www.sitepoint.com/using-traits-in-php-5-4.
- PHP Manual "Traits" @ http://php.net/manual/en/language.oop5.traits.php.
More OOP
Cloning Object
PHP provides a keyword clone
to copy an object, which performs a shadow-copy. If __clone()
magic method is defined in the class, it will be run after the shadow-copy.
__autoload()
[TODO]
Namespace
Can you have two versions of Circle
class in your program? Yes, by placing them into different namespaces.
A namespace (called package in Java) groups the related classes, interfaces, functions and constants. It tries to:
- resolve naming conflict;
- provide aliases for long names.
These keywords are used in namespace management:
namespace ...
use ... [as ...]
Defining a Namespace
To define a namespace, write "namespace identifier
" as the FIRST statement in your PHP file, which sets the "current" namespace. For example,
<?php namespace MyProject; // FIRST statement // Set the current namespace. // A namespace can contain classes, interfaces, constants, and functions. class MyClass { .... } const MY_CONSTANT = 2.17; function myFunction() { ..... } ?>
You can define more than one namespaces in one file. But don't do it for best practice.
Global Space
Any entity defined under no namespace belongs to global space.
Sub-namespace
PHP supports so-called sub-namespace, with names separated by back-slash, e.g., "namespace MyProject\ZBox\ModSec
". Take note that there is no leading back-slash.
It is a best practice to keep your source in directory that matches the namespace. For example, namespace MyProject\ZBox\ModSec
shall be kept in Path/To/MyProject/ZBox/ModSec.
Again, take note that PHP uses back-slash in namespace.
Referencing Entities in Namespace
To reference an entity in a namespace, you could:
- Use the fully-qualified name: e.g.,
$a = new \MyProject\ZBox\ModSec\Circle
. Take note that it begins with a back-slash. - Use the unqualified name: e.g.,
$a = Circle
. This will be resolved toCurrentNamespace\Circle
. - Use a partially-qualified name: e.g.,
$a = ModSec\Circle
(without a leading back-slash). This will be resolved toCurrentNamespace\ModSec\Circle
. Partially-qualified name is messy, and should be avoided.
To access an entity in another namespace outside the current namespace, use the fully-qualified name.
To access an entity in global space outside the current namespace, prefix the entity with a leading backslash. For example, \strlen('hello')
.
[TODO] Example
Magic Constant __NAMESPACE__
The magic constant __NAMESPACE__
contains the name of the current namespace (in string). In global space, __NAMESPACE__
contains an empty string.
Importing with "use ..."
You can invoke the use
operator to import a class, an interface or a namespace. Once an entity is imported, you can access it using its entity name, instead of the fully-qualified name. (This is similar to the import
statement in Java; or using
in C#.) PHP 5.6 supports the import of functions and constants as well. For example,
namespace MyProject\ZBox; // Set the current namespace use JoeProject\YBox\Circle; // Now you can simply refer to it as Circle // Take note that there is no leading back-slash use AnotherNamespace\Subnamespace\SubSubSpace; // Now you can simply refer to it as SubSubSpace use strlen; // A function in the global space // Now you can refer to it as strlen, instead of fully-qualified name \strlen
Aliasing with "use ... as ..."
Furthermore, you can define an alias in the form of "use FullyQualifiedName as alias
". For example,
namespace MyProject\ZBox;
use JoeProject\ABox\CircleWithASuperLongName as Circle;
// Now you can refer to it as Circle
Functions/Constants fall back to Global Space
An unqualified class name is resolved to the current namespace. To use a class outside the current namespace, you need to use the fully-qualified name.
An unqualified function name and constant is similarly resolved to the current namespace. However, if it cannot be resolved, function/constant will fall back to the global space.
REFERENCES & RESOURCES
- PHP mother site @ http://www.php.net; "PHP Manual" @ http://php.net/manual/en/index.php; "PHP Language Reference" @ http://www.php.net/manual/en/langref.php.