将变量$this绑定到可调用对象字段的最短方法是什么?

What's the shortest way to bind variable $this to a callable object field?

提问人: 提问时间:5/1/2022 最后编辑:user3840170 更新时间:5/1/2022 访问量:210

问:

我将变量与 method(第 12-13 行)绑定到 my 和 methods(第 4 行和第 7 行),以便它们可以在 的实例中引用自己的成员字段(第 2-3 行)。它有效,但我觉得这有点乏味。$thisClosure::bind()getName()getAge()stdClass

是否有任何特殊变量或内置函数可以在不调用 method 的情况下引用 my 和 methods(第 4 行和第 7 行)中的当前实例?或者,是否有任何解决方法(如果有)?stdClassgetName()getAge()Closure::bind()

PHP代码

$human = (object) [
    'name' => 'John Doe',
    'age'  => 25,
    'getName' => function() {
        var_dump($this->name);
    },
    'getAge' => function() {
        var_dump($this->age);
    },
];

$human->getName = Closure::bind($human->getName, $human);
$human->getAge = Closure::bind($human->getAge, $human);

print_r($human);

($human->getName)();
($human->getAge)();

示例输出

stdClass Object
(
    [name] => John Doe
    [age] => 25
    [getName] => Closure Object
        (
            [this] => stdClass Object
 *RECURSION*
        )

    [getAge] => Closure Object
        (
             [this] => stdClass Object
 *RECURSION*
        )

)
string(8) "John Doe"
int(25)
php 关闭 stdclass

评论

2赞 M. Eriksson 5/1/2022
考虑到 stdClass 中的所有属性都是公共的,为什么要为 getter 方法而烦恼呢?如果要使用具有某些特定逻辑的类,只需创建一个具有所需功能的类,而不是尝试修改 stdClass。
0赞 5/1/2022
在某些特殊情况下,它可能有用,但出于显而易见的原因,不一定用于 getter 方法。我可以遍历结果以动态地将方法绑定到变量,但是如果有一些特殊变量指向 的当前实例,那就太好了。get_object_vars()$thisstdClass
0赞 user3840170 5/1/2022
这听起来像是一个想要解决的愚蠢问题。为什么不直接编写自己的类呢?
0赞 5/1/2022
如果只需要一个自定义对象作为参数传递,那么使用类声明可能会大材小用。
0赞 user3840170 5/1/2022
为什么要矫枉过正?PHP有匿名类,专门用于这个场合。

答:

0赞 KIKO Software 5/1/2022 #1

我认为你应该提出一个更好的理由来解释你为什么要这样做。也就是说,确实有点乏味。你可以做一些事情,但我怀疑你会喜欢它。它是这样的:Closure::bind()

$human = (object) [
    'name' => 'John Doe',
    'age'  => 25,
    'getName' => function($object) {
        var_dump($object->name);
    },
    'getAge' => function($object) {
        var_dump($object->age);
    },
];

($human->getName)($human);
($human->getAge)($human);

请参见: PHP fiddle

在这里,你承认,在创建时,函数并不知道它们是对象的一部分,什么时候才有意义。因此,您稍后提供所需的对象作为参数,一切都很好。$this

同样,创建一个普通的类会更可取,如果只是因为它更容易理解。请记住,你写代码是为了做某事,但也因为它是向自己和他人传达你的意图的一种方式。

我想到了另一种方法来做到这一点。也不是你想要的,但它有点工作:

$human = (object) [
    'name' => 'John Doe',
    'age'  => 25,
    'getName' => function() {
        global $human;
        var_dump($human->name);
    },
    'getAge' => function() {
        global $human;
        var_dump($human->age);
    },
];

($human->getName)();
($human->getAge)();

请参见: PHP fiddle

评论

0赞 5/1/2022
是的。这正是我的第一次尝试,然后我曾经避免传递每个方法调用的实例。Closure::bind()stdClass
0赞 KIKO Software 5/1/2022
@TheGoodGameLife 我同意必须作为参数提供并不好,但除非你能提出一个更好的理由来将数组转换为对象,并以这种方式使用,否则我认为这是最好的。问题的上下文可能很重要。因为现在是你的对象的一个属性,如果没有一些真正的摆弄,就不能指望它充当该对象的有效方法。$human$thisgetName
0赞 5/1/2022
非常感谢您的第二个解决方案!谢谢。尽管该变量在范围之间不会灵活。我完全忘记了那个关键词。$humanglobal
1赞 user3840170 5/1/2022 #2

首先:尽管问题机构这样称呼它们,但不是方法。在 PHP 中,方法和字段位于不同的命名空间中:方法总是在类上查找,而字段在实例上查找。如果调用表达式看起来像 和 而不是 和 ,它们将查找相应的方法,当然这些方法不存在,因此它们会失败。getNamegetAge$human->getName()$human->getAge()($human->getName)()($human->getAge)()stdClass

此外,一旦读取了字段值,从中读取该值的对象将被丢弃,并且不再使用;获得的值恰好是可调用的,这没有区别。由于对象被丢弃,因此在闭包内没有任何东西可以绑定变量。这与 JavaScript 不同,JavaScript 的方法与字段完全相同,它们共享一个命名空间,并且调用刚刚在对象上查找的函数会将该对象绑定到被调用的函数的主体中。$thisthis

我认为你真正想要完成的事情最好通过匿名类来实现:

$human = new class {
    public $name = 'John Doe';
    public $age = 25;

    public function getName() {
        var_dump($this->name);
    }

    public function getAge() {
        var_dump($this->age);
    }
};

$human->getName();
$human->getAge();

这实际上使方法接收适当的绑定。getNamegetAge$this

如果你坚持,你甚至可以让你的匿名类成为子类,尽管我看不出有什么特别的原因。stdClass

评论

0赞 5/1/2022
谢谢你的努力!我认为它们与 JavaScript 中的对象文字相对相似。好吧,我错了。无论如何,感谢您澄清关闭。我只是在探索 .stdClassstdClass
0赞 KIKO Software 5/1/2022
是的,我虽然你来自另一种语言。Javascript 在许多方面与 PHP 有很大不同,它有不同的用途。尝试将 Javascript 编程模式应用于 PHP 可能不是一个好主意。我更喜欢这个匿名类示例,下一步是为此使用一个更通用的命名类