PHP: предотвращение создания переменной экземпляра вне класса

В приведенном ниже PHP-классе я понимаю, что $ test не будет доступен извне этого класса.

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

Но мы сможем определить новые переменные экземпляра, как показано ниже. Есть ли хитрость, чтобы остановить это?

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

2

Решение

Используя магические методы (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

Для справки, пожалуйста, смотрите гид

1

Другие решения

Довольно безопасное решение. Вам следует избегать использования этих методов __set, потому что они не заботятся о закрытых / защищенных свойствах. Используйте отражение класса, чтобы увидеть, является ли свойство общедоступным и доступным для __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;
1

«Волшебный метод» __set (если объявлено) вызывается при записи данных в недоступные свойства.

Вы можете использовать это в своих интересах, чтобы предотвратить создание необъявленных свойств:

<?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 выше (который объявлен как private), вызовы будут также перенаправляться через магический метод __set. Без метода __set это приведет к фатальной ошибке.

Тем не менее, написать Foo::bar (объявлено публично выше) НЕ будет маршрутизироваться через магический метод __set.

Если вы хотите применить этот тип строгого поведения во многих классах, вы можете реализовать это как черту:

trait Upsetter
{
public function __set($name, $value)
{
throw new Exception('Strictly no writes to inaccesible and undeclared properties.');
}
}

class Bob
{
use Upsetter;
}
-1
По вопросам рекламы [email protected]