我已经设计实现了一个表示多种策略的策略类(Strategy)。每当创建此类策略的一个实例时,它会接收一个函数作为参数。然后,这个函数会被关联到相应的策略对象上,这样一来,在匿名函数内部就可以使用 $this 来引用当前策略对象。下面是一个具体的例子:
$a = new Strategy(function () {
$this->getName(); // Strategy 1. $this refers to $a within this function.
});
在策略(Strategy)类的构造方法内部:
public function __construct(Closure $strategy)
{
self::initCounter();
$this->strategy = $strategy(...)->bindTo($this);
$this->name = 'Strategy ' . self::$strategyCounter->getNextStrategyNumber();
}
initCounter方法用于初始化counter,它是一个简单的私有静态字段,存储的是StrategyCounter类的对象。该对象仅包含策略数量以及获取下一个编号的方法getNextNumber()和减小策略计数的方法decrementStrategyCounter()。
其工作原理很简单:
当创建一个新的策略时,默认会赋予一个名称:"策略 X",其中X代表下一个策略的编号。例如:
$a = new Strategy(function () {}); // Name = Strategy 1
$b = new Strategy(function () {}); // Name = Strategy 2
// and so on.
出现问题的点在哪里?我期望达成什么样的目标?
同时,我也期望确保策略的名称不会被持续占用。也就是说,当某个策略对象被销毁或不再引用时,计数器应当递减,以便于新创建的策略能够继续使用类似于以下形式的可用名称:
$a = new Strategy(function () {}); // Name = Strategy 1
$b = new Strategy(function () {}); // Name = Strategy 2
unset($b); // $b is unset => Counter decremented => Default name for next Strategy should be with number 2.
$c = new Strategy(function () {}); // Name = Strategy 2
遗憾的是,在闭包中存在对策略对象的引用,因此无法利用__destruct()方法达到自动递减计数器的目的。
我所做的尝试
我原本认为或许应当在析构函数里先移除闭包,但这并没有起作用:
public function __destruct()
{
unset($this->strategy);
self::$strategyCounter->decrementStrategyCounter();
}
这是因为实际上析构函数并未被执行。我的理解是这样的:
$a = new Strategy(function () {}); // Name = Strategy 1
$b = new Strategy(function () {}); // Name = Strategy 2
unset($b); // $b isn't unset, because Strategy still exists, because was bind to Closure within that Strategy, and since this is the case, no destuctor is called.
$c = new Strategy(function () {}); // Name = Strategy 3 Blehh ;C
// The script ends, all Strategies are removed one by one.