intahwebz / weaver
组合编程的实验。
Requires
- php: >=5.4.0
- danack/danack-code: ~2.4.2
- intahwebz/core: >=0.2.4
Requires (Dev)
- danack/auryn: ~0.14
- mikey179/vfsstream: v1.2.0
- mockery/mockery: 0.9.1
- monolog/monolog: 1.4.0
- phpunit/phpunit: 4.1.3
- whatthejeff/nyancat-phpunit-resultprinter: ~1.2
README
组合编程的实验。受https://github.com/Ocramius/ProxyManager和https://github.com/ejsmont-artur/phpProxyBuilder的启发
为什么?
上面列出的两个项目都是好主意,但存在严重的局限性。phpProxyBuilder无法生成正确的类型提示信息,这完全阻止了我使用它。
ProxyManager很棒,但与其他代码交互时有问题,似乎使得调试代码变得极其困难。我也看不到如何实现缓存代理。
本项目试图生成各种装饰类版本,目标是
-
在如何使用它们方面具有极大的灵活性。
-
保留调试代码的能力。
-
心理和代码重量都低。
-
保持类型提示完整,以便Auryn DI可以正确工作。
示例
我们有一个类,我们想能够计时'executeQuery'的调用
class TestClass {
function __construct($statement, $createLine){
$this->statement = $statement;
$this->createLine = $createLine;
}
function executeQuery($queryString, $foo2) {
echo "executing query!";
return 5;
}
}
用包含计时器的'class'进行编织
<?php
namespace Weaver\Weave;
use Intahwebz\Timer;
class TimerProxy {
private $timer;
function __construct(Timer $timer) {
$this->timer = $timer;
}
function reportTimings() {
$this->timer->dumpTime();
}
}
并用一点胶水将两者绑定
$timerWeaving = array(
'executeQuery' => array(
'$this->timer->startTimer($queryString);',
'$this->timer->stopTimer();'
),
);
产生装饰类
<?php
namespace Example;
use Intahwebz\Timer;
class TimerProxyXTestClass extends \Example\TestClass
{
private $timer = null;
public function executeQuery($queryString, $foo2)
{
$this->timer->startTimer($queryString);
$result = parent::executeQuery($queryString, $foo2);
$this->timer->stopTimer();
return $result;
}
public function reportTimings()
{
$this->timer->dumpTime();
}
public function __construct($statement, $createLine, \Intahwebz\Timer $timer)
{
parent::__construct($statement, $createLine);
$this->timer = $timer;
}
}
因为我使用真正的DI,现在我可以将配置更改以包含
$injector->alias(TestClass::class, TimerProxyXTestClass::class);
并且附加计时器的代理版本将在原类被使用的任何地方使用。
待办事项
-
弄清楚如何处理工厂,因为不得不为每种组合创建一个新的工厂真的很糟糕。例如,CachedTimedStatementWrapperFactory用于创建缓存、计时、语句包装器工厂。
-
写一篇关于此与猴子补丁http://en.wikipedia.org/wiki/Monkey_patch的区别的文章。简而言之,猴子补丁仅运行时,无法调试,类型安全性不高。
术语
-
源类 - 需要修改其行为的原始类。
-
装饰类 - 将用于装饰源类的类。
-
装饰类 - 编织的结果。
备注
我应该从Ocramius/ProxyManager实施的一组示例
延迟加载值持有者(虚拟代理)访问拦截器值持有者空对象幽灵对象 - 用于延迟加载延迟引用 - wat远程对象
保护代理类APIProtectionProxy extends API { protected $count = 0; public function __construct(API $api, $limit) { $this->api = $api; $this->limit = $limit; }
public function doStuff() {
$this->count();
return $this->api->doStuff();
}
private function count() {
if (++$this->count > $this->limit) {
throw new RemoteApiLimit('STAHP!');
}
}
}