在下面给出的PHP类中,我知道$ class将无法从该类外部访问。
class Resource {
private $test;
public function __construct() {
echo "in init";
$test = "new val";
}
}
但我们将能够定义新的实例变量,如下所示。有没有办法阻止这个?
$r = new Resource();
$r->val = "value";
答案 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}}