在PHP7匿名类中访问外部变量

在PHP7匿名类中访问外部变量,php,Php,PHP7增加了对的支持,但是我似乎找不到关于相关范围问题的任何信息。我知道我可以在callables/closures中使用use关键字来访问外部作用域变量(比如function()use($outer){//do work with$outer}),有没有办法在匿名类中实现这一点 我希望能够做到这一点,而不依赖于匿名类构造函数参数,也不需要在实例化后添加setter方法或公共属性来存储值 下面是一个例子: $outer = 'something'; $instance = new class

PHP7增加了对的支持,但是我似乎找不到关于相关范围问题的任何信息。我知道我可以在callables/closures中使用
use
关键字来访问外部作用域变量(比如
function()use($outer){//do work with$outer}
),有没有办法在匿名类中实现这一点

我希望能够做到这一点,而不依赖于匿名类构造函数参数,也不需要在实例化后添加setter方法或公共属性来存储值

下面是一个例子:

$outer = 'something';

$instance = new class {
    public function testing() {
        var_dump($outer); // would like this to dump the string 'something'
    }
};

在这种情况下,访问外部变量的唯一方法是使用$\u GLOBAL(我不推荐)。如果您不想使用构造函数或setter方法,我的建议是在匿名类中使用静态变量,并在包含匿名类实例的变量消耗后设置值(因为该类是匿名的,所以在此之前不可能定义静态值)。这样做,您就有了一个更好的控件和一个静态变量,但在某种程度上这并不常见,每次创建一个新的匿名类时,实例及其值都属于接收“新对象”的变量,您最好创建一个真正的类。。但请遵循一个静态值和匿名类的示例:

$i = new class {

    public static $foo;
};

var_dump($i::$foo); //No value

$i::$foo = "Some value";

var_dump($i::$foo); //Has value

希望有帮助

另一种解决方案可能是

$outer = 'something';

$instance = new class($outer) {

    private $outer;

    public function __construct($outer) {
        $this->outer = $outer
    }

    public function testing() {
        var_dump($this->outer); 
    }
};

php变量范围文档中有一些说明

此脚本不会生成任何输出,因为echo语句引用$a变量的本地版本,并且未在此范围内为其赋值。您可能会注意到,这与C语言有点不同,因为C中的全局变量自动可用于函数,除非由局部定义特别重写。这可能会导致一些问题,因为人们可能会无意中更改全局变量。在PHP中,如果要在函数中使用全局变量,则必须在函数中声明全局变量

在php中,类中的方法可以访问的范围被限制在整个类的内部,不能访问到其他范围。因此,我认为您想要的效果不会在php中实现,至少在php组决定更改php的默认行为之前是这样


当然,您仍然可以通过将变量声明为全局变量来使用它。

即使OP确实声明它们希望避免使用
公共属性和
匿名类构造函数参数
,但公认的答案正是这样,因此下面是一个使用公共属性的示例,可以通过私有属性和setter来改进,以保持封装:

class Foo {
    public function executionMethod() {
        return "Internal Logic";
    }
}

$foo = new Foo();
var_dump("Foo's execution method returns: " . $foo->executionMethod());

$bar = new class extends Foo {
    public $barVal;
    public function executionMethod() {
        return $this->barVal;
    }
};
$bar->barVal = "External Logic";
var_dump("Bar's execution method returns: " . $bar->executionMethod());
如果无法重写继承的类的构造函数,我发现这很有用

这将输出:

string(46) "Foo's execution method returns: Internal Logic"
string(46) "Bar's execution method returns: External Logic"

如果您希望匿名类能够访问受保护或私有的外部属性和方法,那么可以利用闭包继承它们在其中定义的作用域这一事实,并将它们绑定到一些实现无缝行为的神奇方法中

这是未经测试的,但我很确定它会起作用:

$class = new class {
    /**
     * @var \Closure
     */
    public static $outerScopeCall;

    /**
     * @var \Closure
     */
    public static $outerScopeGet;

    /**
     * @param string $name
     * @param array $arguments
     * @return mixed
     */
    public function __call(string $name, array $arguments = [])
    {
        $closure = static::$outerScopeCall;
        return $closure($name, $arguments);
    }

    /**
     * @param string $name
     * @param array $arguments
     * @return mixed
     */
    public function __get(string $name)
    {
        $closure = static::$outerScopeGet;
        return $closure($name);
    }
};

$class::$outerScopeCall = function (string $name, array $arguments = []) {
    return $this->$name(...$arguments);
};

$class::$outerScopeGet = function (string $name) {
    return $this->$name;
};

$call
闭包将有权从定义它的位置访问
$this
的定义,而不是将它传递到方法中的位置?所以你没有使用属性,你没有使用构造函数?那你能用一个匿名函数吗?在不知道这个用例是什么的情况下,我们只能推测。@JonStirling我目前使用的是一个匿名函数,但我想使用一个带有接口的匿名类,这样我就可以对可调用的更改进行推理used@AbraCadaver比如,想想Java的语言特性,您可以在匿名类中访问外部作用域变量-只是想知道PHP是否有一些特殊的语法需要用于访问这些变量(如可调用项/闭包的
use
关键字),我希望
新类用法($outer){..}
能很好地工作,谢谢!解决了动态扩展一个类的问题,该类在框架中使用了一些关键的静态调用。这里需要注意的是,当您使用带有
use($someOuterVar)
语句的匿名函数时,您也在那里分配一个静态变量。就像在函数(是的,您可以这样做)或类定义中使用
static
关键字一样。也就是说,我认为这应该是公认的答案,它最符合闭包所确立的惯例。我认为这是目前可用的“最佳”选项,因此我将其标记为答案。我认为这是实现这一点的最佳方法。谢谢!:)这太烦人了,为什么PHP不能像普通语言一样提供对闭包中外部作用域变量的直接访问?@AntoineMarques他们忙于改变生活的进步,比如不赞成“@obe,我发誓我用PHP编程已经超过10年了,专业上已经将近9年了,我从来没有遇到过