PHP: предотвращение создания переменной экземпляра вне класса - PullRequest
0 голосов
/ 21 мая 2018

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

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

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

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

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

При записи данных в недоступные свойства вызывается «магический метод» __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 выше (который объявлен закрытым), вызовы также будут маршрутизироваться с помощью магического метода __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;
}
0 голосов
/ 21 мая 2018

Довольно безопасное решение.Вам следует избегать использования этих методов __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;
0 голосов
/ 21 мая 2018

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

Для справки см. гид

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...