jgswift / magery

使用 traits 的 PHP 5.4+ 魔术拦截系统

0.1.1 2014-09-11 10:46 UTC

This package is not auto-updated.

Last update: 2024-09-28 15:44:29 UTC


README

使用 traits 的 PHP 5.4+ 魔术拦截系统

Build Status Scrutinizer Code Quality Latest Stable Version License Coverage Status

描述

magery 提供了一个 trait 框架,可以用来钩入对象魔法,即 __get、__set、__unset、__isset 和 __call。

安装

使用 composer 在命令行中安装

php composer.phar require jgswift/magery:0.1.*

使用 composer.json 安装 composer

{
    "require": {
        "jgswift/magery": "0.1.*"
    }
}

依赖

  • php 5.4+

使用方法

基本

class Foo
{
    use Magery\Mage;
   
    private $bar;
   
    public function __construct()
    {
        $this->read('bar', function(){
            throw new \Exception('Don\'t touch my bar!');
        });
    }
    
    public function touchBar()
    {
        $this->bar;
    }
}

$foo = new Foo();
$foo->touchBar(); // Fatal error: Uncaught exception 'Exception' with message 'Don't touch my bar!'

写入

可以注册一个写入回调来保护变量不被覆盖(即使在类的作用域内)

$this->write('bar', function() {
  throw new \Exception('Don\'t write to my bar!');
});
        
public function writeToBar() {
  $this->bar = 'somethingElse';
}        
        
$foo = new Foo();
$foo->writeToBar(); // Fatal error: Uncaught exception 'Exception' with message 'Don't write to my bar!'        

读取

可以通过事件拦截任何对象的属性或方法。
注意:多个已注册的事件将按添加的顺序(FIFO)触发,直到事件返回一个响应值。

class Foo {
    use magery\Mage;

    public function __construct() {
        $this->read('bar', function(){
            return 'baz';
        });

        // Shortcut method
        $this->read('buzz', function() {
            return 'bar';
        });
    }
}
        
        
$foo = new Foo();
echo $foo->bar;     // 'baz'
echo $foo->buzz;    // 'bar'

存在性

class User { 
    private $firstName;
    private $lastName;

    function __construct($firstName, $lastName) { /* ... */ }
}

$user = new User('John', 'Doe');
$user->exists('lastName', function()use(&$c) {
    return isset($this->lastName);
    // do something extra for existence check
});

var_dump(isset($user->lastName)); // true

移除

$user = new User('Joe','Smith');
$user->remove('name', function()use(&$c) {
    unset($this->name);
    // do something extra for remove
});

unset($user->name);

var_dump(isset($user->name)); // false

结果缓存

如果事件返回响应,则可以将其缓存以减少未来读取的执行时间。

public $bar = 'Bill';

public function __construct()
{
  $this->read('bar', function(){
    sleep(1);
    return microtime();
  }, true);     // pass in "true" here (defaults to false)
}
        
        
$foo = new Foo();
var_dump($foo->bar === $foo->bar);   // true

辅助方法作用域

除了 magery 函数默认受保护外,所有事件都是全局注册的。

<?php
class Foo
{
    use Magery\Mage {magery as public;}   // allow public event registration
   
    public $bar;
}

$foo = new Foo();

$foo->read('bar', function(){
    throw new \Exception('Don\'t touch my bar!');
});

$foo->bar;  // Fatal error: Uncaught exception 'Exception' with message 'Don't touch my bar!'

调用

与读取类似,调用魔法也可能缓存结果以减少未来调用的执行时间。

<?php
class Foo
{
    use Magery\Mage;
}

$foo = new Foo();

$foo->call('bar', function() {
    sleep(1);
    return microtime();
},true);

var_dump($foo->bar() === $foo->bar());   // true

可数组的对象

对于数组而不是对象,通过结合使用 ArrayAccess 和 MageAccess trait 将提供与数组语法相同的魔法机会

<?php
class Foo implements ArrayAccess {
    use Magery\MageAccess;
}

$foo = new Foo();

$foo->read('bar', function() {
    return 'baz';
});

var_dump($foo['bar']);   // baz

自定义魔法处理器

您可以通过选择性地使用 traits 来创建自定义处理器。
此示例类仅包含写入魔法,所有其他操作都原生执行,不中断。自定义对象必须使用 Magery\Object,并且您可以选择任何组合的 Traits/ReadTraits/WriteTraits/RemoveTraits/Exists trait 来应用特定的魔法功能。

<?php
class Foo
{
    use Magery\Object, Magery\Traits\Write;
}

$foo = new Foo();

$foo->write('bar', function($v){
    $this->baz = $v;
});

$foo->bar = 'somethingImportant';

var_dump($foo->baz);   // somethingImportant