描述

我实现了一个代表各种策略的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方法初始化计数器,这是一个简单私有静态字段,对象为StrategyCounter类,只有几个策略和方法来获取下一个数字-getNextNumber()并递减数字-decrementStrategyCounter()

操作原理很简单:

在创建新的Strategy时,它会收到默认名称:"Strategy 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()来实现这一点,因为对Strategy的引用在Closure

我所try 的

我想也许我应该首先删除析构函数中的闭包,但这并不起作用:

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.

推荐答案

您几乎不可能有一个简单的接口,它期望存在一个run()方法.由此,您可以使用$this上下文来调用它.每个$strategy实例都有自己的$this作用域.

演示:https://3v4l.org/eCtZU

interface StrategyInterface {
    public function run();
}

class Strategy implements StrategyInterface
{
    protected ?string $value = null;
    public function __construct(private Closure $closure)
    {
        $this->value = (string) rand(1, 100);
    }

    public function run()
    {
        $this->closure->call($this);
    }
}

for ($i = 0; $i < 10; ++$i) {
    $strategy = new Strategy(function() {
        var_dump($this->value);
    });

    $strategy->run();
}

这里是一个使用静态计数器的更复杂的例子:

演示:https://3v4l.org/smcDi

interface StrategyInterface
{
    public function run();
}

class Strategy implements StrategyInterface
{
    protected ?string $value = null;
    private static $counter = 0;

    public function __construct(private Closure $closure)
    {
        echo "Strategy Counter: ", ++self::$counter, PHP_EOL;
        $this->value = (string)rand(1, 100);
    }

    public function run()
    {
        $this->closure->call($this);
    }

    public function __destruct()
    {
        echo "Strategy Counter: ", --self::$counter, PHP_EOL;
    }
}

$strategy1 = new Strategy(function () {
    var_dump($this->value);
});

$strategy2 = new Strategy(function () {
    var_dump($this->value);
});

$strategy3 = new Strategy(function () {
    var_dump($this->value);
});


$strategy1->run(); // counter still 3, because 3 are created
$strategy1 = null; // destroy the first strategy, counter is 2
$strategy2->run();
unset($strategy2); // destroy the second strategy, counter is 1
$strategy3->run();

$strategy4 = new Strategy(function () { // create a new strategy, counter is 2
    var_dump($this->value);
});

// program ends, counter goes down to 0

Php相关问答推荐

产品ACF值在WooCommerce我的账户订单的附加列中为空

使用箭头函数语法时,在回调范围内无法访问变量变量(警告:未定义的变量)

在WooCommerce我的帐户部分添加带有自定义链接的自定义菜单项

Laveel Livewire Get Groupby姓名列表

根据未用于变体的产品属性隐藏WooCommerce发货方式

当主页和帖子的缩略图相同时,如何减少主页和帖子的缩略图

如何将LARAVEL模块路径和项目路径合并,因为当我使用模块路径时,它们会覆盖项目路径

将数据推入所有子数组条目

Laravel 10.x在到达控制器之前将查询参数强制转换为正确的类型

$this->;db->;update();CodIgnitor中的功能不工作

在 PHP MySQL 中自动生成账单编号

如何使用 PHP 将带有图像的文本上传到 Linkedin?

WooCommerce 回购自定义插件:如何更新用户钱包?

PHP API - 本地主机中的 SSL 证书问题

通过ajax发送数据到下拉列表未完全设置为所选

在 WooCommerce 管理变量产品中启用其他变体图像

PHP 中的curl -F request=@file.xml

如何在 Laravel 中修改嵌套数组的键?

无法在 Laravel 10 中安装 jenssegers/mongodb

从 d-m-Y 日期格式 laravel 计算月份 = 01 的列的总和