Site icon JS Tech Road

PHP Object Oriented Programming Quick Reference Guide

Source from https://www.logicbig.com/

Features/SyntaxDescription/examples

class

A 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’ keyword

To create an instance of a class, new keyword is used new MyClass();

pseudo-variable $this

The reference to the current object, only used within the class.

Object operator ->

Used when calling a method or accessing a property on an object instance. It is used with $this as well.

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

Visibility

The visibility keywords (public, protected, private) determines how an object properties/methods are accessible:

  • public: can be accessed anywhere.
  • protected: can be accessed by the class and subclasses only.
  • private: can be accessed by the class only.

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 constants

Just 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 methods

Class 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 destructors

A constructor function __construct() is a special (magic) function which is automatically called when an object instance is created with ‘new’ keyword. A constructor can have any number of user defined parameters. Constructors should ideally be used to initialize object

A destructor is a special function __destruct() which is automatically called when object is deleted from memory by garbage collector.

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/destruct

Parent 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 keyword

Similar 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 overriding

Method 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 classes

An 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

Interfaces

Like 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 interfaces

A 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

Traits

A 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..

  1. A trait is defined using keyword trait. It is similar to a class, but cannot be instantiated it’s own.
    trait MyTrait {
    ...
    }
  2. A trait can have properties and magic methods. It can also have static properties and methods.
  3. To use them in a class use keyword use followed by the trait name. A class can have multiple comma separated traits.
    class MyClass{
     use MyTrait1, MyTrait2;
     ...
    }
  4. In case of conflicts, the class overrides trait functions, but if those functions are defined in a parent class of the current class then traits overrides them.
  5. If two traits have a method with the same name, a fatal error is produced. We can resolve the conflict by using insteadof operator:
    class MyClass{
     user MyTrait1, MyTrait2{
      MyTrait2::aMethod insteadof MyTrait1;
     }
      ...
    }
  6. Since insteadof operator excludes one of the method, we can re-include the excluded method by using as operator which gives an alias to the method.
    class MyClass{
      use MyTrait1, MyTrait2{
       MyTrait2::aMethod insteadof MyTrait1;
       MyTrait1::aMethod as otherMethod;
      }
    }
    $a = new MyClass();
    $a->aMethod();//calls MyTrait2::aMethod
    $a->otherMethod();//calls MyTrait1::aMethod
  7. We can also change the visibility of a method using as operator:
    class MyClass{
     use MyTrait {
     aMethod as private aPrivateMethod;
     }
    }
  8. A trait can use other traits too:
    trait MyTrait{
     use MyOtherTrait;
    }
  9. A trait can have abstract methods too. In that case classes using them have to implement the method.
<?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 keyword

A 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

  • The comparison operator == compares the objects by their property values and by types. Two objects are equal if they are instances of the same class and have same property values and, even though they are different references.
  • The identity operator === compares the object by their references. The object variables are identical if and only if they refer to the same instance of the same class.
<?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 iteration

By 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 Classes

For 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 methods

These 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.

  • __set(): is triggered when an inaccessible property is assigned a value.
  • __get(): is triggered when an inaccessible property is accessed.
  • __isset(): is triggered when calling built-in functions isset() or empty() on inaccessible properties..
  • __unset(): is triggered when calling built-in function unset() on inaccessible properties.
<?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(), __callStatic

This is a way to dynamically create object methods which do not exist or are inaccessible.

  • __call(): is triggered when calling an inaccessible method of an object.
  • _callStatic(): is triggered when calling an inaccessible static method methods of a class.
<?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 variables

The 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 info

The 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" }
Exit mobile version