PHP:阻止类外的实例变量创建

时间:2018-05-21 12:10:37

标签: php instance-variables

在下面给出的PHP类中,我知道$ class将无法从该类外部访问。

class Resource {
    private $test;
    public function __construct() {
       echo "in init";
       $test = "new val";
    }
}

但我们将能够定义新的实例变量,如下所示。有没有办法阻止这个?

$r = new Resource();
$r->val = "value"; 

3 个答案:

答案 0 :(得分:1)

使用魔术方法(namly __set)你可以告诉班级“这里是否设置了这个,忽略它”,例如;

<?php

class Resource {
    private $test;
    public function __construct() {
       echo "in init";
       $this->test = "new val";
    }

    public function __set($name, $val)
    {
        // If this variable is in the class, we want to be able to set it
        if (isset($this->{$name})
        {
            $this->{$name} = $val;
        }
        else
        {
            // Do nothing, add an error, anything really
        }
    }
}

$resource = new Resource();
$resource->foo = "bar";
echo $resource->foo; // Will print nothing

供参考,请参阅the guide

答案 1 :(得分:1)

更安全的解决方案。你应该避免使用那些__set方法,因为它们不关心私有/受保护的属性。使用类反射,查看属性是否为public且可以访问__set。小例子如下。

    <?php

class Resource {
    private $test = 55;
    public $foo;
    public $bar;

    public function __set($name, $value)
    {
        if(isset($this->{$name})) {
            $reflection = new ReflectionObject($this);
            $properties = $reflection->getProperties(ReflectionProperty::IS_PUBLIC);
            $isPublic = false;
            /** @var ReflectionProperty $property */
            foreach ($properties as $property) {
                if ($property->getName() == $name) {
                    $isPublic = true;
                    break;
                }
            }
            if ($isPublic) {
                $this->{$name} = $value;
            } else {
                //is private, do not set
                echo 'Im private, dont touch me!';
            }
        } else {
            // not here
            echo 'Im not here';
        }
    }
}

$resource = new Resource();
$resource->test = 45;

答案 2 :(得分:-1)

魔术方法&#39;在将数据写入不可访问的属性时调用<?php class Foo { public $bar; private $baz; public function __set($name, $value) { throw new Exception('Strictly no writes to inaccesible and undeclared properties.'); } } $f = new Foo; $f->bar = 'hello'; $f->qux = 'earth'; (如果声明)。

您可以利用此优势来防止创建未声明的属性:

Fatal error: Uncaught Exception: Strictly no writes to inaccesible and undeclared properties. in /var/www/stackoverflow/so-tmp-f2.php:20 Stack trace: #0 /var/www/stackoverflow/so-tmp-f2.php(26): Foo->__set('qux', 'earth') #`1 {main} thrown in /var/www/stackoverflow/so-tmp-f2.php on line 20

输出:

Foo::baz

如您所见,上述内容在尝试写入未声明的属性时会抛出异常。

如果您尝试写入另一个不可访问的属性(在类似范围内),如上面的Foo::bar(被声明为私有),则调用也将通过__set魔术方法进行路由。如果没有__set方法,将导致致命错误。

但是,对trait Upsetter { public function __set($name, $value) { throw new Exception('Strictly no writes to inaccesible and undeclared properties.'); } } class Bob { use Upsetter; } (上面声明为public)的写入不会通过__set魔术方法进行路由。

如果要在许多类中强制执行此类严格行为,可以将上述内容实现为特征:

{{1}}