在PHP 7匿名类中访问外部变量

时间:2018-02-27 21:53:25

标签: php

PHP 7添加了对anonymous classes的支持,但我似乎无法找到有关相关范围问题的任何信息。我知道我可以使用带有callables / closures的replace()关键字来访问外部作用域变量(比如use),有没有办法用匿名类做到这一点?

我希望能够在不依赖匿名类构造函数参数的情况下完成此操作,而无需在实例化之后添加setter方法或公共属性来存储值。

以下是一个例子:

function() use ($outer) { // do work with $outer }

5 个答案:

答案 0 :(得分:9)

另一个解决方案可能是

$outer = 'something';

$instance = new class($outer) {

    private $outer;

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

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

答案 1 :(得分:2)

在这种情况下访问外部变量的唯一方法是使用$ _GLOBAL(我不推荐)。如果你不想使用构造函数或setter方法,我的建议是在匿名类中使用一个STATIC变量,并在属性之后将值设置为包含匿名类实例的变量(不能定义静态值)之前,因为班级是匿名的..)。这样做,你有一个更好的控制和一个静态变量,但在某种程度上这不是很平常,每当你创建一个新的匿名类时,实例和它的值属于接收“新对象”的VARIABLE,也许你可以更好地创建一个真正的类..但是请遵循一个带有静态值和匿名类的示例:

$i = new class {

    public static $foo;
};

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

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

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

希望它有所帮助!

答案 2 :(得分:1)

http://php.net/manual/en/language.variables.scope.php

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

  

此脚本不会产生任何输出,因为echo语句引用$ a变量的本地版本,并且未在此范围内为其分配值。您可能会注意到,这与C语言略有不同,因为C中的全局变量会自动提供给函数,除非被本地定义明确覆盖。这可能会导致一些问题,因为人们可能会无意中更改全局变量。在PHP中,如果要在函数中使用全局变量,则必须将其声明为全局变量。

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

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

答案 3 :(得分:0)

即使OP确实声明他们希望避免使用public propertiesanonymous class constructor arguments,但可接受的答案恰恰是,所以这里是一个使用公共财产的示例,可以通过使用私有财产和维护封装的二传手:

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"

答案 4 :(得分:0)

如果您希望匿名类访问受保护或私有的外部属性和方法,则可以利用以下事实:闭包继承了其定义的作用域,并将它们绑定到一些魔术方法中以实现无缝连接行为。

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

$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的定义