coapsyfactor/decorator

PHP 装饰器,在执行前动态添加方法和属性,并正确设置作用域和 $this。

dev-master 2019-01-24 01:13 UTC

This package is auto-updated.

Last update: 2024-09-24 14:04:03 UTC


README

PHP 装饰器

在执行时,动态向对象添加方法,并使用提供的正确上下文和作用域。

使用方法

可以被装饰的类 必须 使用 Decoratable 特性。

Decoratable 特性依赖于魔法方法 __call__get,因此直接使用它们会破坏 Decorator 的功能。

要设置自定义的 __call__get,请使用 __onCall__onGet

基本装饰

向某个对象添加方法。

    <?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
严格对象类型装饰

严格对象类型装饰将确保被更改的对象是提供名称的实例或子类。

    <?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
定义方法装饰

在附加装饰器方法时,脚本将检查原始方法是否存在。原始方法 必须 与装饰器方法同名,且不带前缀。

原始方法将被作为装饰器方法的第一参数传递,它将包含附加的上下文和作用域。执行很简单,只需调用例如 $original(),其中 $original 是装饰器方法的第一参数。

默认前缀: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
使用类装饰

对象也可以用某个类进行装饰,提供的装饰器类中找到的所有静态方法都将应用于目标对象。

使用正确的方法访问数据,脚本提供在类定义外部访问私有属性的方式。

    <?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
        
装饰属性

向对象添加动态属性

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