PHP Blog http://blog.dev-php.site Snippets and guides Thu, 08 Sep 2022 17:41:05 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.2 PHP Self Type Hint http://blog.dev-php.site/php-self-type-hint/ Sun, 01 Dec 2019 21:30:21 +0000 http://blog.dev-php.site/?p=172 Continue reading PHP Self Type Hint]]> Self Function Parameter

The self type hint refers to the current class not to the instance ie. an object of the same type (the current class or a subclass). Every variable passed must be an instanceof the same class.


function foo(self $bar)		// PHP 5.0+
function foo(self $bar = null)	// PHP 5.1+


class foo { 
	function aMethod(self $obj){
		echo var_dump($obj);	
	}
}
class bar extends foo{}
class baz extends bar{}

$e = new foo();
$f = new bar();
$g = new baz();

$e->aMethod($e); // object(foo)#1 (0) { }
$e->aMethod($f); // object(bar)#2 (0) { }
$e->aMethod($g); // object(baz)#3 (0) { }


Self Return Type

If you use self return type it doesn’t matter if the method returns a cloned version of the object, (immutable objects). The object that is returned is of the same type as the object on which the method is called. In the example below whatever is returned will be of type Foo.

function foo(): self	// PHP 7.0+
function foo(): ?self	// PHP 7.1+

interface Foo {
    /**
     * @param Bar $bar
     * @return self
     */
    public function setBar(Bar $bar): self;
}

class Foo implements Foo
{
    /**
     * {@inheritdoc} 
     */
    public function setBar(Bar $bar): Foo
    {
        // ...
        return $this;
    }
}


class ClassName
{
    public function foo(): ?self
    {
        return new ClassName();
    }

    public function bar(): ?self
    {
        return null;
    }
}

$instance = new ClassName();
$instance->foo();
$instance->bar();


]]>
Closure vs Callable Type Hinting http://blog.dev-php.site/closure-vs-callable-type-hinting/ Thu, 28 Nov 2019 09:16:26 +0000 http://blog.dev-php.site/?p=169 Continue reading Closure vs Callable Type Hinting]]>
  • function foo(callable $bar) PHP 5.4+
  • function foo(callable $bar = null) PHP 5.4+
  • function foo(): callable PHP 7.0+
  • function foo(): ?callable PHP 7.1+
  • When type hinting, a closure must be an anonymous function, where a callable also can be a normal method/function.

    • Closure is a class and callable is a type.
    • The callable type accepts anything that can be called
    
    function callableFunc(Callable $callback) {
        $callback();
    }
    
    function closureFunc(Closure $closure) {
        $closure();
    }
    
    function anyFunc(Callable $callable) {
        $callable();
    }
    
    function testFunc() {
        echo 'Hello, World!', "
    "; } $testClosure = function(){ echo 'Hello, World!', "
    "; }; // gettype($testClosure); object // var_dump($testClosure); object(Closure)#1 (0) { } try{ closureFunc($testClosure); // Hello, World! callableFunc("testFunc"); // Hello, World! anyFunc($testClosure); // Hello, World! callableFunc($testClosure); // Hello, World! closureFunc("testFunc");// Argument 1 passed to closureFunc() must be an instance of Closure, string given } catch(TypeError $e){ echo $e->getMessage(), "
    "; } finally { echo "Reachable statement"; }
    ]]>
    PHP Overloading vs Overriding http://blog.dev-php.site/php-overloading-vs-overriding/ Thu, 28 Nov 2019 08:34:54 +0000 http://blog.dev-php.site/?p=166 Continue reading PHP Overloading vs Overriding]]> Overloading:

    Types of Overloading in PHP:

    Property Overloading

    All overloading methods must be defined as Public.

    • __set(): triggered while initializing overloaded properties.
    • __get(): triggered while using overloaded properties with PHP print statements.
    • __isset(): This magic method is invoked when we check overloaded properties with isset() function
    • __unset(): Similarly, this function will be invoked on using PHP unset() for overloaded properties.
    
    class MyClass
    {
        /**  Array for overloaded data.  */
        private $data = array();
    
        public function __set($name, $value)
        {
            $this->data[$name] = $value;
        }
        
        public function __get($name)
        {
            return $this->data[$name];
        }
    
        public function __isset($name)
        {
            return isset($this->data[$name]);
        }
    
        public function __unset($name)
        {
            unset($this->data[$name]);
        }
    }
    $obj = new MyClass;
    $obj->name = "John Doe";
    echo $obj->name; // John Doe
    
    
    Method Overloading

    Function overloading contains same function name and that function preforms different task according to number of arguments. For example, find the area of certain shapes where radius are given then it should return area of circle if height and width are given then it should give area of rectangle and others. Like other OOP languages function overloading can not be done by native approach. In PHP function overloading is done with the help of magic function __call(). This function takes function name and arguments. Most of the magic methods will be triggered in object context except __callStatic() method which is used in a static context.

    • __call() – triggered while invoking overloaded methods in the object context.
    • __callStatic() – triggered while invoking overloaded methods in static context.
    
    class MyClass { 
    
        public function __call($name, $arguments) { 
              
            echo "Calling object method '$name' "
                . implode(', ', $arguments). "\n"; 
        } 
      
          
        public static function __callStatic($name, $arguments) { 
              
            echo "Calling static method '$name' "
                . implode(', ', $arguments). "\n"; 
        } 
    } 
          
    
    $obj = new MyClass; 
    
    $obj->myMethod('in object context'); // Calling object method 'runTest' in object context
      
    MyClass::myMethod('in static context');  // Calling static method 'runTest' in static context
    
    

    Overriding:

    In function overriding, both parent and child classes will have same function name and number of arguments. It is used to replace parent method in child class. The purpose of overriding is to change the behavior of parent class method. Creating two methods with the same name and same parameters in inherited classes is called overriding.

    
    class ParentClass { 
          
        function process(array $data):array
    	{ 
            $array = array_filter($data, function($v){
    	    return $v < 3;
    	}); 
    	return $array;
        } 
    } 
       
    class ChildClass extends ParentClass { 
          
        function process(array $data):array
        { 
            return array_map(function($v){
    	    return $v * 2;
            }, $data); 
        }  
    }
    $parent = new ParentClass();
    $child = new ChildClass();
    $filtered = $parent->process(range(1,5));
    $doubled = $child->process(range(1,5));
    echo '
    ';
    var_dump($filtered, $doubled);
    /*
    Results
    
    array(2) {
      [0]=>
      int(1)
      [1]=>
      int(2)
    }
    array(5) {
      [0]=>
      int(2)
      [1]=>
      int(4)
      [2]=>
      int(6)
      [3]=>
      int(8)
      [4]=>
      int(10)
    }
    */
    
    ]]> Law of Demeter in PHP http://blog.dev-php.site/law-of-demeter-in-php/ Thu, 28 Nov 2019 07:35:11 +0000 http://blog.dev-php.site/?p=163 Continue reading Law of Demeter in PHP]]> Principle of Least Knowledge

    The Law of Demeter is a design guideline with as goal to create loose coupling between objects. If an object knows too much about another (knowledge how to access the third object from the first object) is considered as bad design, because the object has to unnecessary traverse from top to bottom of the chain to get actual dependencies it needs to work with.

    • A method of an object can call methods of that object
    • A method can call a method of its parameters
    • A method can call a method of any objects created or instantiated by that method
    • A method can call a method of objects that are dependencies of the methods object
    • A method can call a method of a global variable that is accessible by the object of the method

    The One Dot Principle Violation

    class InvoiceController
    {
        public function create(User $user, $invoiceTotal)
        {
            try {
                $user->getAccount()
                    ->getBalance()
                    ->substractSum($invoiceTotal);
            } catch (Exception $e) {
                // handle expcetion
            }
        }
    }
    

    This introduces tight coupling, which we should always be trying to avoid in our codebase. Tight coupling reduces the quality of our application code, making it harder to maintain. When we modify one piece of tightly coupled code, then when need to review and modify all the other members of the tightly coupled relationships.

    class InvoiceController 
    {
        use App\User;
        use App\Invoice;
    
        public function __construct(User $user, Invoice $invoice){
            $this->user = $user; 
            $this->invoice = $invoice;
        }
    
        public function processPayment()
        {
            try {
                $this->user->payInvoice($this->invoice);
                // The other methods getAccount(), getBalance() and substractSum($invoiceTotal)
                // will be handled in there own class/methods NO CHAINING
            } catch(Exception $e) {
                // handle exception
            }
        }
    }
    

    The knowledge of the inner process of the invoice payment now is encapsulated in User class. The Law of Demeter gives us a guideline how to achieve loose coupling in our code and helps to properly encapsulate the knowledge of some complicated operations or logic into the places where they should be.

    ]]>
    PHP Higher Order Functions http://blog.dev-php.site/php-higher-order-functions/ Thu, 28 Nov 2019 07:24:57 +0000 http://blog.dev-php.site/?p=161 Continue reading PHP Higher Order Functions]]> A higher-order function or, a first-class functions, is defined as one that can accept other functions as arguments or return another function. Both are intimately related, as the ability of a language artifact to be passed in as an argument or returned from a functions hinges on it being considered just another object. This also means, of course, that functions can be assigned to variables.

    Assigning a function to a variable

    $concat2 = function (string $s1, string $s2): string {
        return $s1. ' '. $s2;
    };
    $concat2('Hello', 'World');  //-> 'Hello World'
    

    This code takes the anonymous function and assigns it to the variable $concat2. Alternatively, you can check for the presence of a function variable using is_callable():

    is_callable($concat2) // true
    

    Returned from a function

    Functions can also be returned from other functions, ‘notice the : callable type hint. This is an extremely useful technique for creating families of functions. It’s also the main part of implementing argument currying

    function concatWith(string $a): callable {
       return function (string $b) use ($a): string {
          return $a . $b;	
       };
    }
    
    $helloWith = concatWith('Hello');
    $helloWith('World'); //-> 'Hello World'
    

    A callable as a parameter

    A php function argument can be a callable variable

    // Use case 1
    function apply(callable $func, $a, $b) {
       return $func($a, $b);
    }
    
    $add = function (float $a, float $b): float {
       return $a + $b;
    };
    
    $divide = function (float $a, float $b): float {
       return $a / $b;
    };
    
    apply($add, 5, 5); //-> 10
    apply($divide, 5, 5); //-> 10	
    
    // Use case 2
    
    function apply(callable $func): callable {
       return function($a, $b) use ($func) {
          return $func($a, $b);
       };
    }
    
    ]]>
    PHP Template Method Pattern and Class Hierarchies http://blog.dev-php.site/php-template-method-pattern-and-class-hierarchies/ Wed, 28 Aug 2019 04:01:15 +0000 http://blog.dev-php.site/?p=153 Continue reading PHP Template Method Pattern and Class Hierarchies]]> You can tell when you are not using class hierarchies when you start duplicating fields and methods. By cutting and pasting methods, if there was a defect in the Person class, there would most likely be a defect in the Employee class as well because the implementation was copied between the two.

    class Person
    {
        private $name;
    
        public function setName($name)
        {
            $this->name = $name;
        }
    }
    
    class Employee
    {
        private $name;
    
        public function setName($name)
        {
            $this->name = $name;
        }
    }
    

    Template Method Pattern

    The Template Method Pattern is a behavioral design pattern that allows you to defines a skeleton of an algorithm in a base class and let subclasses override the steps without changing the overall algorithm’s structure. This also leverages inheritance. Inheritance allows functionality to be built up from related classes. Each class provides specialized support that’s specific to a class’s purpose. It’s common that functionality in an object-oriented application is provided by class hierarchies rather than single, unrelated classes.

    name = $name;
        }
    
        /**
        * The optional method should by default do nothing.
        */    
        abstract public function introduceSelf();
    
    }
    
    class Person extends PersonTemplate
    {
        public function introduceSelf()
        {
            echo 'I am a...';
        }
    }
    
    class Employee extends PersonTemplate
    {
        public function introduceSelf()
        {
            echo 'My job is a...';
        }
    }
    
    function getWho(PersonTemplate $e){
    	$e->introduceSelf();
    }
    $employee = new Employee();
    $person = new Person();
    
    getWho($employee);
    getWho($person);
    
    ]]>
    PHP Class Cohesion and Separation of Concerns http://blog.dev-php.site/php-class-cohesion-and-separation-of-concerns/ Wed, 28 Aug 2019 03:57:01 +0000 http://blog.dev-php.site/?p=150 Continue reading PHP Class Cohesion and Separation of Concerns]]> Separation of Concerns (SoC)

    SoC means that you try to separate objects by what they should be really concerned about and is a design principle that splits an application up into its relevant categories (concerns).

    Cohesion

    Cohesion is the extent to which proximate procedures are related to one another. Highly cohesive Object oriented designs are focused and organized in related modules. Learning about “concerns” is important in determining how to organize functions and classes to be highly cohesive. If methods and classes are highly cohesive, you are able to easily split off entire groups without affecting the design. Designs with high cohesion offer the opportunity for lower coupling.

    When a design has low cohesion, it has classes and methods that are not grouped well. To avoid low cohesion don’t write relatively generic classes AND follow the single responsibility principle.

    Low Cohesion

    
    class Utils
    {
        public static function formatAddress($formatType, $address1,
            $address2, $city, $state)
        {
            return "some address string";
        }
    
        public static function formatPersonName($formatType, $givenName,
            $familyName)
        {
            return "some person name";
        }
    
        public static function parseAddress($formatType, $val)
        {
            // real implementation would set values, etc...
            return new Address();
        }
    
        public static function parseTelephoneNumber($formatType, $val)
        {
            // real implementation would set values, etc...
            return new TelephoneNumber();
        }
    }
    
    

    High Cohesion

    
    class AddressUtils
    {
        public static function formatAddress($formatType, $address1,
            $address2, $city, $state)
        {
            return "some address string";
        }
    
        public static function parseAddress($formatType, $val)
        {
            // real implementation would set values, etc...
            return new Address();
        }
    
    }
    
    class PersonUtils
    {
        public static function formatPersonName($formatType, $givenName,
            $familyName)
        {
            return "some person name";
        }
    
        public static function parsePersonName($formatType, $val)
        {
            // real implementation would set values, etc...
            return new PersonName();
        }
    }
    
    
    ]]>
    PHP Loose Coupling and Dependency Injection http://blog.dev-php.site/php-loose-coupling-and-dependency-injection/ Wed, 28 Aug 2019 03:26:00 +0000 http://blog.dev-php.site/?p=146 Continue reading PHP Loose Coupling and Dependency Injection]]> Dependency Injection is a software design pattern that allows avoiding hard-coding dependencies and makes possible to change the dependencies both at runtime and compile time. Always inject, (pass object as an argument) dependencies into the constructor. Creating instances within the constructor creates a tight coupling between the two classes.

    Version 1 is documented, extendable and testable, as the MyService class does not care how the Config object was made, and it can be interchanged with any instance of IConfig and it can be mocked. If we add a new parameter to Config’s constructor, we then have to modify every class where we create a Config object.

    Version 2 is highly coupled, and not easily testable.

    Version 1

    class MyService {
        public function __construct(IConfig $config){
            $this->config = $config;  // 
        } 
    }
    
    // If any dependencies change or object is not created, the problems are not brought to the service class object.
    $deps = [1,2];
    $config = new Config($deps);
    $service = new MyService($config);
    
    // ** NOT
    $service = new MyService(new Config($deps));
    

    The MyService class does not necessarily need to know about any IConfig implementation, it should be confined to its own functionality only. So writing any Config class code in MyService class doesn’t make it modular. This also defeats the Single responsibility principle.

    Version 1 is now:
    • Modular: The Dependency Injection helps create completely self-sufficient classes or modules
    • Testable: It helps write testable code easily
    • Maintainable: Since each class becomes modular, it becomes easier to manage it

    Version 2

    Now you have just inherited any problems the Config obj might have

    class MyService {
        public function __construct(){
            $this->config = new Config();
        } 
    }
    

    Using Factories

    If there are NO dependencies required, it can be helpful to use a Factory.

    class ServiceFactory
    {
        private $storage = [];
    
        public function create( $name )
        {
            if ( false === array_key_exists( $name, $this->storage ))
            {
                $instance = new $name;
                $this->storage[$name] = $instance;
            }
    
            return $this->storage[$name];
        }
    
    }
    
    ]]>
    Value Objects in PHP http://blog.dev-php.site/value-objects-in-php/ Wed, 21 Aug 2019 21:41:42 +0000 http://blog.dev-php.site/?p=140 Continue reading Value Objects in PHP]]> Explanation:
    The equality of two Value Objects is not based on identity (them being the same object, checked with the operator ===), but on their content. Value Objects are almost always immutable so that they can be shared between other domain objects. Mutating a Value Object means creating a new one, often with a Factory Method, that being said “Once set, the value object cannot be modified without changing its identity”.

    Benefits:

    • Readability – the types of things that we pass to different parts of our application match to what they represent in our domain and it’s clearer what kind of value is expected without having to check in the code
    • Validation – ensure every existing value object is in a correct state. This means that we don’t have to check them when we use them.
    • Type hinting – we can type hint primitive types for parameters.
    • Immutability – One of the main causes of bugs in software is when the state of an object inadvertently changes, or its reference becomes null. Immutable objects can be passed around to any function and their states will always remain the same.

    Value Objects are easier to create, test, use and maintain, they also compose related attributes as an integral unit. Value Objects are completely replaceable when the measurement or description changes and can be compared with others through value equality with Side-Effect-Free behavior.

    When creating a new value object we need to make sure that it has a valid state, and that the class can not be extended.

    final class Person
    {
        /** @var string */
        private $name;
     
        public function __construct(string $name)
        {
            if (strlen($name) < 3 || !ctype_alpha($name)) {
                throw new InvalidArgumentException("Person class name property has to consist of at least three letters");
            }
            $this->name = $name;
        }
     
        public function equals(Person $person): bool
        {
            return $this === $person;
        }
     
        public function getName()
        {
            return $this->name;
        }
    }
    
    
    // Using setters for validation
    
    final class Person
    {
        /** @var string */
        private $name;
     
        public function __construct(string $name)
        {
    	$this->setName($name);
        }
    
        private function setName(string $name)
        {
            if (strlen($name) < 3 || !ctype_alpha($name)) {
                throw new InvalidArgumentException("Person class name property has to consist of at least three letters");
            }
            $this->name = $name;
        }
     
        public function equals(Person $person): bool
        {
            return $this === $person;
        }
     
        public function getName()
        {
            return $this->name;
        }
    
    }
    
    
    ]]>
    Pure vs impure PHP functions http://blog.dev-php.site/pure-vs-impure-php-functions/ Wed, 21 Aug 2019 21:35:08 +0000 http://blog.dev-php.site/?p=138 Continue reading Pure vs impure PHP functions]]> Pure functions
    • There are no globals and values are not passed by reference
    • They have no side effects
    • They dont use loops (for, for each, while…)

    Impure functions

    • Mutate global state
    • May modify their input parameters
    • May throw exceptions
    • May perform any I/O operations: i.e. external resources (databases, network, file system…)
    • May produce different results even with the same input parameters.
    • May have side effects

    Pure functions

    always return the same output given the same input.

    function add(int $a, int $b) : int
    {
      return $a + $b; //should return a sum of $a and $b
    }
    

    Impure functions

    A function whose return value is one modified outside of its scope is considered impure. All functions whose return values are contingent on the return values of functions like date() and random() as well as those dependent on global variables and file interactions are impure.

    
    $counter = 0;
    
    function inc() {
      global $counter;
      return $counter++; //the global variable renders this impure
    }
    
    function timeAdvance() {
      return time() + 5; //returns a new value every time it is run
    }
    
    function dbUpdate($orm, $value) {
      return $orm
        ->update('some query', $value)
        ->execute();
    } //interacts with a database and is impure
    
    
    ]]>