PHP Classes
elePHPant
Icontem

PHP Decorator Pattern: Implement the decorator pattern using a trait

Recommend this page to a friend!
  Info   View files View files (12)   DownloadInstall with Composer Download .zip   Reputation   Support forum   Blog    
Last Updated Ratings Unique User Downloads Download Rankings
2019-01-23 (9 hours ago) RSS 2.0 feedNot enough user ratingsTotal: 49 This week: 49All time: 9,389 This week: 6Up
Version License PHP version Categories
decorator 1BSD License7.2Data types, Design Patterns, PHP 7, T...
Description Author

This package can implement the decorator pattern using a trait.

The trait defines the __call and __get functions to allow adding dynamically new functions and variables to the original class, so when such functions or variables are accessed by applications, the trait will access the functions and variables that were added.

The trait can also call the __onCall or __onGet functions of the original class when the called functions or variable were not defined.

  Performance   Level  
Name: Aleksandar Zivanovic <contact>
Classes: 12 packages by
Country: Serbia Serbia
Innovation award
Innovation award
Nominee: 2x

Details

PHP Decorator

Dynamically add methods on objects with provided proper context and scope when executing.

Usage

Class that can be decorated MUST use `Decoratable` trait.

`Decoratabletrait relies on magic methods__calland__get, therefor using them directly is not possible without breakingDecorator` functionality.

To set custom `__calland__getuse__onCalland__onGet` instead.

Basic Decoration

Add method to some object.

    <?php

        class User
        {
            use Decoratable;
            
            private $firstName;
            private $lastName;
            
            public function __construct(string $firstName, string $lastName) {
                $this->firstName = $firstName;
                $this->lastName = $lastName;
            }
        }
        
        $user = Decorator::decorate(new User('Brown', 'Fox'), 'getFullName', function (): string {
            return "{$this->firstName} {$this->lastName}";
        });
        
        echo $user->getFullName(); // Brown Fox

Strict object type decoration

Strict object type decoration will ensure that object that is being changed is instance or subclass of provided name.

    <?php

        class User
        {
            use Decoratable;
            
            private $firstName;
            private $lastName;
            
            public function __construct(string $firstName, string $lastName) {
                $this->firstName = $firstName;
                $this->lastName = $lastName;
            }
            
            private function getFirstName(): string
            {
                return $this->firstName;
            }
            
            public function getLastName(): string
            {
                return $this->lastName;
            }
        }
        
        $user = Decorator::decorate(new User('Brown', 'Fox'), 'getFullName', function (): string {
            return "{$this->getFirstName()} {$this->getLastName()}";
        }, User::class);
        
        echo $user->getFullName(); // Brown Fox

Defined method decoration

While attaching decorator method, script will check if original method exists. Original method MUST be called same as decorated method without prefix.

Original method will be passed as first argument of decorated method, it will contain attached context and scope. Execution is simple, just by calling e.g `$original()where$original` is first parameter of decorated method.

`Default prefix: decorated`

    <?php

        class User
        {
            use Decoratable;
        
            private $firstName;
            private $lastName;
        
            public function __construct(string $firstName, string $lastName) {
                $this->firstName = $firstName;
                $this->lastName = $lastName;
            }
        
            public function getFullName(): string
            {
                return "{$this->firstName} {$this->lastName}";
            }
        }
        
        $user = Decorator::decorate(
            new User('Brown', 'Fox'), 'decoratedGetFullName',
            function (callable $original, string $title): string {
                return "{$title}. {$original()}";
            }
        );
        
        echo $user->decoratedGetFullName('Mr'); // Mr. Brown Fox

Decorate with class

Object can also be decorated with some class, all static methods found in provided decorator class will be applied to target object.

Using proper way of accessing data, script provides access to private properties outside class definition.

    <?php
    
        class EntityHydrator
        {
            public function hydrate(callable $context, array $data): void
            {
                // $context callable provide us with instance of target as parameter
                // in this case called $postEntity, and script has access to its private properties
                // $this is instance of target object that is being decorated
                $context(function () use ($data) {
                    // id, firstName, lastName are private properties
                    $this->id = $data['id'] ?? null;
                    $this->firstName = $data['firstName'] ?? null;
                    $this->lastName = $data['lastName'] ?? null;
                }, User::class);
            }
        }

        $user = Decorator::decorateWithClass(new User(), EntityHydrator::class);
        $user->hydrate(['firstName' => 'Criss', 'lastName' => 'Popo']);
        
        echo $user->getFirstName(); // Criss
        

Decorate property

Add dynamic property to an object

    <?php

        class User
        {
            use Decoratable;
        
            private $firstName;
            private $lastName;
        
            public function __construct(string $firstName, string $lastName) {
                $this->firstName = $firstName;
                $this->lastName = $lastName;
            }
        
            public function getFullName(): string
            {
                return "{$this->firstName} {$this->lastName}";
            }
        }
    
        $user = Decorator::decorate(new User('Brown', 'Fox'), 'title', 'Dr');
        
        echo $user->title; // Dr

  Files folder image Files  
File Role Description
Files folder imageexample (2 files, 2 directories)
Files folder imagesrc (2 files)
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file composer.lock Data Auxiliary data
Accessible without login Plain text file php_decorator.iml Data Auxiliary data
Accessible without login Plain text file README.md Doc. Class source

  Files folder image Files  /  example  
File Role Description
Files folder imageClassDecorators (2 files)
Files folder imageEntities (2 files)
  Accessible without login Plain text file example.php Example Example script
  Accessible without login Plain text file index.php Example Example script

  Files folder image Files  /  example  /  ClassDecorators  
File Role Description
  Accessible without login Plain text file CRUDDecorator.php Example Example script
  Accessible without login Plain text file EntityHydrator.php Example Example script

  Files folder image Files  /  example  /  Entities  
File Role Description
  Accessible without login Plain text file CommentEntity.php Example Example script
  Accessible without login Plain text file PostEntity.php Example Example script

  Files folder image Files  /  src  
File Role Description
  Plain text file Decoratable.php Class Class source
  Plain text file Decorator.php Class Class source

 Version Control Unique User Downloads Download Rankings  
 100%
Total:49
This week:49
All time:9,389
This week:6Up