Source from https://www.logicbig.com/
Features/Syntax | Description/examples |
---|---|
classA class is a blueprint from which we create object instances. A class mainly contains properties and methods. Variables and functions are called properties and methods respectively in OOP world. ‘new’ keywordTo create an instance of a class, new keyword is used pseudo-variable $thisThe reference to the current object, only used within the class. Object operator | <?php class MyClass { // defining a property public $myProperty = 'a property value'; // defining a method public function display() { echo $this->myProperty; } } $var = new MyClass(); $var->display(); ?>Output: a property value |
VisibilityThe visibility keywords (public, protected, private) determines how an object properties/methods are accessible:
A property must be defined with one of the above visibility keywords. A method defined without any of them will have public visibility by default. | <?php class MyClass { public $var1 = 'public var'; protected $var2 = 'protected var'; private $var3 = 'private var'; function printHello() { echo $this->var1 . '<br>'; echo $this->var2 . '<br>'; echo $this->var3 . '<br>'; } } $obj = new MyClass(); echo $obj->var1 . '<br>'; // prints public var $obj->printHello(); // prints all // if uncommented followings will produce fatal errors /* * echo $obj->var2; // Fatal Error * echo $obj->var3; // Fatal Error */Output: public var public var protected var private var |
Class constantsJust like defining other constants (outside of a class) using ‘const’ keyword, we can also define them inside a class. The default visibility of class constants is public. Constants are allocated once per class, and not for each class instance. Scope Resolution Operator (::)Instead of using ->, double colon allows access to static and constant. This operator is also used to access super class features. Using ‘self’Instead of using $this, the self keyword is used to access constants within the class. Generally, for all class level access self should be used and for all current object instance access $this should be used within the class. | <?php class MyClass { const PI = 3.14159; function showPI() { echo self::PI . "<br>"; } } echo MyClass::PI . "<br>"; $class = new MyClass(); $class->showPI(); echo $class::PI . "<br>"; ?>Output: 3.14159 3.14159 3.14159 |
static properties and methodsClass properties and methods can be declared with static keyword which makes them class level features and we don’t need a class instance to access those features. Like class constants we access static properties/methods with double colon (::) and to access them within class we use self keyword. $this is not available inside a static method. By default static features have ‘public’ accessibility. For static variable initialization, the same rules apply as const expressions. | <?php class MyClass { static $var = 'a static property'; static function aMethod() { return self::$var; } } echo MyClass::$var . '<br>'; echo MyClass::aMethod(); ?>Output: a static property a static property |
Constructors and destructorsA constructor function A destructor is a special function Objects are deleted as soon as no references of them used in the program, or during the shutdown sequence. Destructors are typically used for cleanup, state persistence, etc. | <?php class MyClass { private $prop; function __construct($var) { echo 'In constructor of ' . __CLASS__ . '<br>'; $this->prop = $var; } public function displayProp() { echo $this->prop .'<br>'; } function __destruct() { echo 'destroying ' . __CLASS__; } } $a = new MyClass('the property value'); $a->displayProp(); ?>Output In constructor of MyClass the property value destroying MyClass |
Inheritance:Inheritance is the process of extending an existing class (parent class) by a new class (subclass) using extends keywords. A subclass inherits all properties and methods from it’s super (parent) class except for private ones. Inheritance is used for code reuse and polymorphism. PHP allows single inheritance (at most one super class) | <?php class MyParentClass { protected $var = 'a super call property'; public function display() { echo $this->var . '<br>'; } } class MySubclass extends MyParentClass { public function getVar() { return 'returning ' . $this->var; } } $a = new MySubClass(); $a->display(); echo $a->getVar(); ?>Output: a super call property returning a super call property |
Inheritance and Construct/destructParent class constructor/destructor are not implicitly called if the child class defines them as well. In order to run a parent constructor (or destructor), a call to parent::__construct() within the child constructor is required. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method. parent keywordSimilar to ‘self’ keyword which is used to access class level static and constant features, parent is used to access super class level features from subclass that includes construct/destruct and overridden methods (next topic). | <?php class A { protected static $x = 'value x'; function __construct() { echo 'In constructor of ' . __CLASS__ . '<br>'; } } class B extends A { function __construct() { parent::__construct(); echo parent::$x .'<br>'; echo 'In constructor of ' . __CLASS__ . '<br>'; } } $b = new B();Output: In constructor of A value x In constructor of B |
| |
Method overridingMethod overriding is the process where a subclass redefine a parent class method to change it’s behavior. The signature should exactly be the same. In case if we want to access parent level features from within a subclass then we will use parent:: | <?php class A { function aMethod() { return "aMethod from A"; } } class B extends A { function aMethod() { return "aMethod from B, ". parent::aMethod(); } } $a = new A; echo($a->aMethod()); echo('<br>'); $b = new B; echo($b->aMethod()); ?>Output aMethod from A aMethod from B, aMethod from A |
Abstract classesAn abstract class cannot be instantiated. They provide base class abstract implementation to be extended to provide some specific behavior. An abstract thing doesn’t exist in reality e.g. an animal doesn’t exists as a concrete thing but an specialization e.g. dog does exist. An abstract class definition starts with abstract keyword. An abstract class can defined method(s) without body. In that case, we have to use abstract keyword in the method signature. A subclass must override abstract methods or otherwise should be ‘abstract’ themselves. | <?php abstract class A{ abstract protected function aMethod(); public function doSomething(){ $this->aMethod(); } } class B extends A{ protected function aMethod(){ echo 'aMethod called'; } } $b = new B(); $b->doSomething();Output: aMethod called |
InterfacesLike an abstract class, Interface is another way to define abstract type. Interfaces define methods without implementation. They don’t have to use abstract keyword. To define an interface we use interface keyword instead of class. All methods in an interface should be public. Class implementing interfacesA class may implement one or more comma separated interfaces by using implements keyword. The class must implement all interface methods or otherwise should be declared abstract. Interfaces can extend each other by using keyword extends | <?php interface Task { public function runTask(); public function anotherMethod(); } abstract class TaskImpl implements Task { public function runTask() { echo $this->anotherMethod(); } } class TaskImpl2 extends TaskImpl { public function anotherMethod() { return "another method running task "; } } $task = new TaskImpl2(); $task->runTask(); ?>Output: another method running task |
TraitsA Trait is intended to reduce some limitations of PHP single inheritance model. A developer can reuse sets of methods freely in several independent classes living in different class hierarchies..
| <?php trait ATrait{ private $var; function __construct($str) { $this->var = $str; } public function aTraitFunction() { echo __METHOD__ . ", from ATrait: $this->var<br>"; } public function aTraitFunction2() { echo __METHOD__ . ", from ATrait: $this->var<br>"; } function __toString() { return __CLASS__ . ", var=$this->var <br>"; } } trait BTrait{ public function aTraitFunction2() { echo __METHOD__ . ", from BTrait: $this->var<br>"; } } class BClass { public function aTraitFunction2() { echo __METHOD__ . ", from BClass: $this->var<br>"; } } class AClass extends BClass { use ATrait, BTrait{ BTrait::aTraitFunction2 insteadof ATrait; } public function aTraitFunction() { echo __METHOD__ . ", frome AClass: $this->var<br>"; } } $a = new AClass('a string'); echo $a; $a->aTraitFunction(); $a->aTraitFunction2();Output: AClass, var=a string AClass::aTraitFunction, frome AClass: a string BTrait::aTraitFunction2, from BTrait: a string |
Final keywordA method declared with final keyword cannot be overridden by a subclass. A class declared with final keyword cannot be extended. | class A { final function display() { echo "displaying in " . __CLASS__; } } class B extends A { function display() { echo "displaying in " . __CLASS__; } } $b = new B(); $b->display();Output: Fatal error: Cannot override final method A::display() in D:\eclipse-workspace\php-oop\final.php on line 13 final class A { } class B extends A { } $b = new B();Output: Fatal error: Class B may not inherit from final class (A) in D:\eclipse-workspace\php-oop\final-class.php on line 5 |
Objects equality
| <?php class MyClass { } function toString($bool) { if ($bool === false) { return 'FALSE'; } else { return 'TRUE'; } } $a = new MyClass(); $b = new MyClass(); $c = $a; echo '<br>$a==$b : ' . toString($a == $b); echo '<br>$a===$b : ' . toString($a === $b); echo '<br>$a==$c : ' . toString($a == $c); echo '<br>$a===$c : ' . toString($a === $c);Output: $a==$b : TRUE $a===$b : FALSE $a==$c : TRUE $a===$c : TRUE |
Object iterationBy default all visible properties can be iterated using foreach loop. To control iteration process we can implement built-in Iterator interface. | <?php class TestClass { public $str = 'a str property'; public $int = 3; protected $str2 = "a protected str property"; private $str3 = "a private str property"; function display(){ foreach($this as $key => $value){ echo "$key => $value <br>"; } } } $a = new TestClass(); $a->display(); echo '----<br>'; foreach($a as $key => $value){ echo "$key => $value <br>"; }Output: str => a str property int => 3 str2 => a protected str property str3 => a private str property ---- str => a str property int => 3 |
Auto-loading ClassesFor a typical PHP application, a developer has to use multiple include statements to include multiple files. Per good practice, there should be a single class in a file. spl_autoload_register function registers any number of autoloaders, enabling for classes and interfaces to be automatically loaded if they are currently not defined. By registering autoloaders, PHP is given a last chance to load the class or interface before it fails with an error. | Assume class A resides in A.php and class B resides in B.php at the same location as this Test.php script: <?php spl_autoload_register(function ($className) { echo "including $className.php <br>"; include $className . '.php'; }); $a = new A(); $b = new B(); including A.php including B.php |
Magic methodsThese special methods get called in response to a particular event or scenario. We just have to implement them in our class. These methods starts with double underscores. We have seen two magic methods above already: __construct() and __destruct(). Here’s the complete list: __construct(), __destruct()__toString(), __set(), __get(), __isset(), __unset(), __call(), __callStatic() __invoke(), __set_state(), __clone(), __sleep(), __wakeup(), and __debugInfo() we are going to explore them in the following sections. | |
String representation of objects__toString()This method should return a string. It’s a way to represent an object as a string. | <?php class MyClass{ private $var = 'a property'; public function __toString(){ return "MyClass: var = '$this->var'"; } } $a = new MyClass(); echo $a;Output: MyClass: var = 'a property' |
| |
Property Overloading__set(), __get(), __isset(), __unset()This is a way to dynamically create object properties which do not exist or are inaccessible.
| <?php class MyClass { private $arr; public function __set($name, $value) { $this->arr[$name] = $value; } public function __get($key) { if (array_key_exists($key, $this->arr)) { return $this->arr[$key]; } return null; } public function __isset($name) { if (isset($this->arr[$name])) { echo "Property $name is set.<br>"; } else { echo "Property $name is not set.<br>"; } } public function __unset($name) { unset($this->arr[$name]); echo "$name is unset <br>"; } } $myObj = new MyClass(); $myObj->name="joe";// will trigger __set var_dump($myObj); echo '<br>'; echo $myObj->name; //will trigger __get echo '<br>'; isset($myObj->name);//will trigger __isset unset($myObj->name);//will trigger __unset var_dump($myObj); ?>Output: object(MyClass)#1 (1) { ["arr":"MyClass":private]=> array(1) { ["name"]=> string(3) "joe" } } joe Property name is set. name is unset object(MyClass)#1 (1) { ["arr":"MyClass":private]=> array(0) { } } |
Method overloading__call(), __callStaticThis is a way to dynamically create object methods which do not exist or are inaccessible.
| <?php class MyClass { public function __call($name, $paramArr) { // do something based on method name and params return "<br>returning result of method: $name , params: " . print_r($paramArr, true) . "<br>"; } public static function __callStatic($name, $paramArr) { // do something based on method name and params return "<br>returning result of static method: $name , params: " . print_r($paramArr, true) . "<br>"; } } $a = new MyClass(); echo $a->someMethod("some arg"); echo MyClass::someStaticMethod("some arg for static method"); ?>Output: returning result of method: someMethod , params: Array ( [0] => some arg ) returning result of static method: someStaticMethod , params: Array ( [0] => some arg for static method ) |
Calling object as a function__invoke() method is triggered when a script tries to call the target object as an function. It can be used to pass a class instance that can act as a closure, or simply as a function that we can pass around, and can invoke it without knowing if it’s an object or without knowing what object it is. | <?php class MyClass { public function __invoke() { //do something on being invoked as a function echo "invoked triggered<br>"; } } function myFunction(Callable $func) { $func(); return "returning from myFunction"; } $a = new MyClass(); //$a() this also works echo myFunction($a);Output: invoked triggered returning from myFunction |
Object Cloning__clone() method of a newly cloned object is triggered just after it has been cloned by using clone keyword. __clone() method allows any necessary properties that need to be changed after cloning. When an object is cloned by using clone keyword, PHP performs a shallow copy of all of the object’s properties. Any properties that are internal object references will not be cloned and will remain references. Using __clone(), we can explicitly cloned internal objects too. There can be an recursive _clone() method calls to achieve deep cloning. | <?php class MyClass { public $var; public function __construct() { $this->var = new MyOtherClass(); } public function __clone() { $this->var = clone $this->var; } } class MyOtherClass { private $str = 'some string'; function getStr() { return $this->str; } } function toString($bool) { if ($bool === false) { return 'FALSE'; } else { return 'TRUE'; } } $a = new MyClass(); $b = clone $a; //using identity operator === to see two '$var' have the same references echo 'are internal objects equal: ' . toString($a->var === $b->var);Output:
are internal objects equal: FALSE
removing __clone() method of MyClass will give output of TRUE, confirming that two $var are still pointing to same reference. |
Serialization__sleep() and __wakeup()__sleep() method triggered when serialize() function is invoke on the target object. serialize generates a storable string representation of a value. To deserialize string to PHP type we use unserialize() function. In that case the magic method __wakeup() is invoked on the target object. The purpose of these two magic methods is to control the ongoing serialization process. __sleep() method returns an array of property names to be serialized. If this method is not defined then all properties are serialized. | <?php class MyClass { public $date; public $str; function __sleep() { return array('date'); } function __wakeup() { echo "wakeup triggered <br>"; } } date_default_timezone_set("America/Chicago"); $a = new MyClass(); $a->date = date("y/m/d"); $s = serialize($a); echo "serialized: <br>"; echo $s; echo "<br>"; echo "unserializing<br>"; $b = unserialize($s); echo 'unserialized object:'; echo var_dump($b); echo "<br>"; echo 'unserialized date: ' . $b->date;Output: serialized: O:7:"MyClass":1:{s:4:"date";s:8:"16/10/25";} unserializing wakeup triggered unserialized object:object(MyClass)#2 (2) { ["date"]=> string(8) "16/10/25" ["str"]=> NULL } unserialized date: 16/10/25 |
Exporting variablesThe magic method __set_state() of a class is produced in the exported string when we use var_export() function on the instance of the target object. A variable can be exported to a parsable string representation by using var_export() function. This method is similar to var_dump() but the difference is that var_export() returns a valid PHP code. Which we can import in our program and can reuse it later. For example:<?php class A{ public $prop = 4; } echo var_export(new A());Output: A::__set_state(array( 'prop' => 4, )) Exported var returns a form which would expect a static method call __set_state() on object A and pass the exported object property array. That happens when we try to convert it to PHP variable again. We are supposed to define __set_state() method in our class and recreate the object instance from the array. One way to reuse the exported string to manually copy paste the code and use it. Another way is to use the function eval(), which is not recommended. | <?php class TestClass { public $var = 4; public static function __set_state($arr) { $a = new TestClass(); $a->var = $arr['var']; return $a; } } $a = new TestClass(); $v = var_export($a, true); echo "exported variable:<br> $v <br>"; echo "<br>importing variable:<br>"; eval('$e=' . $v . ';'); var_dump($e);Output: exported variable: TestClass::__set_state(array( 'var' => 4, )) importing variable: object(TestClass)#2 (1) { ["var"]=> int(4) } |
Controlling debug infoThe magic method __debugInfo() is triggered when we use var_dump() on the target object. If this method isn’t defined on an object, then all public, protected and private properties will be shown. If it is defined, then it should return an associative array of properties which we want to show in var_dump() call. | class TestClass { private $var = 10; private $str = 'a string'; public function __debugInfo() { return ['string' => $this->str]; } } $a = new TestClass(); var_dump($a);Output: object(TestClass)#1 (1) { ["string"]=> string(8) "a string" } |