## Свойства

Переменные-члены класса называются свойствами. В других языках аналогичные элементы называются полями и другими терминами, но в PHP-документации переменные-члены класса называются свойствами. Свойства класса определяют хотя бы одним модификатором (которые описывают разделы «Область видимости», «Ключевое слово static» или начиная с PHP 8.1.0 readonly), за которым начиная с PHP 7.4 следует необязательное, за исключением `readonly`-свойств, объявление типа, после которого идёт стандартное объявление переменной. При объявлении свойства класса переменную возможно инициализировать, но начальное значение переменной потребуется указать как постоянное значение.

> Замечание:

> Устаревший способ объявления свойств класса — ключевое слово `var` вместо модификатора.

> Замечание: Свойство, которое объявили без модификатора раздела «Область видимости», PHP объявит как `public`.

Внутри методов класса доступ к нестатическим свойствам получают через оператор объекта `->` — $this->property, где `property` — имя свойства. Доступ к статическим свойствам получают через оператор двойного двоеточия `::` — self::$property. Дополнительную информацию об отличиях статических свойств от нестатических даёт раздел «Ключевое слово static».

Псевдопеременная $this доступна внутри каждого метода класса, если метод вызывается из контекста объекта. Переменная $this — значение вызывающего объекта.

Пример #1 Объявление свойств

    <?php

    class SimpleClass
    {
       public $var1 = 'hello ' . 'world';
       public $var2 = <<<EOD
    hello world
    EOD;
       public $var3 = 1+2;
       // Неправильное определение свойств:
       public $var4 = self::myStaticMethod();
       public $var5 = $myVar;

       // Правильное определение свойств:
       public $var6 = myConstant;
       public $var7 = [true, false];

       public $var8 = <<<'EOD'
    hello world
    EOD;

       // Без модификатора области видимости:
       static $var9;
       readonly int $var10;
    }

> Замечание:

> Классы и объекты обрабатывают набором функций. Смотрите раздел справки «Функции работы с классами и объектами».

### Объявления типов

Начиная с PHP 7.4.0 определениям свойств разрешается включать «Объявления типов», за исключением типа callable.

Пример #2 Пример типизированных свойств

    <?php

    class User
    {
        public int $id;
        public ?string $name;

        public function __construct(int $id, ?string $name)
        {
            $this->id = $id;
            $this->name = $name;
        }
    }

    $user = new User(1234, null);

    var_dump($user->id);
    var_dump($user->name);

Результат выполнения приведённого примера:

    int(1234)
    NULL

При обращении к типизированному свойству, для которого не определили начальное значение, PHP выбросит исключение Error.

Пример #3 Обращение к свойствам

    <?php

    class Shape
    {
        public int $numberOfSides;
        public string $name;

        public function setNumberOfSides(int $numberOfSides): void
        {
            $this->numberOfSides = $numberOfSides;
        }

        public function setName(string $name): void
        {
            $this->name = $name;
        }

        public function getNumberOfSides(): int
        {
            return $this->numberOfSides;
        }

        public function getName(): string
        {
            return $this->name;
        }
    }

    $triangle = new Shape();
    $triangle->setName("triangle");
    $triangle->setNumberofSides(3);
    var_dump($triangle->getName());
    var_dump($triangle->getNumberOfSides());

    $circle = new Shape();
    $circle->setName("circle");
    var_dump($circle->getName());
    var_dump($circle->getNumberOfSides());

Результат выполнения приведённого примера:

    string(8) "triangle"
    int(3)
    string(6) "circle"

    Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be accessed before initialization

### Readonly-свойства

Начиная с PHP 8.1.0 разрешили объявлять свойства с модификатором `readonly`, который запрещает изменять свойство после инициализации. До PHP 8.4.0 свойство с модификатором `readonly` автоматически получало закрытую видимость для установки значения, и записывать такое свойство можно было только в том же самом классе, в котором свойство объявили. С PHP 8.4.0 свойства с модификатором `readonly` автоматически получают защищённую видимость для установки значения `protected(set)`, поэтому устанавливать значения для такого свойства можно в дочернем классе. Видимость свойства для записи разрешается переопределять вручную.

Пример #4 Примеры readonly-свойств

    <?php

    class Test
    {
        public readonly string $prop;

        public function __construct(string $prop)
        {
            // Правильная инициализация.
            $this->prop = $prop;
        }
    }

    $test = new Test("foobar");

    // Правильное чтение
    var_dump($test->prop); // string(6) "foobar"

    // Неправильное переопределение. Не имеет значения, что присвоенное значение такое же
    $test->prop = "foobar";
    // Error: Cannot modify readonly property Test::$prop

> Замечание:

> Модификатор readonly разрешается применять только к типизированным свойствам. Тип свойства объявляют как Mixed, когда требуется создать readonly-свойство без ограничений типа.

> Замечание:

> Статические readonly-свойства не поддерживаются.

Readonly-свойство разрешается инициализировать только один раз и только из области видимости, в которой свойство объявили. Другое присваивание или изменение свойства приведёт к исключению Error.

Пример #5 Неправильная инициализация readonly-свойств

    <?php

    class Test1
    {
        public readonly string $prop;
    }

    $test1 = new Test1();

    // Неправильная инициализация за пределами закрытой области
    $test1->prop = "foobar";
    // Error: Cannot initialize readonly property Test1::$prop from global scope

> Замечание:

> Нельзя явным образом указывать значение по умолчанию для readonly-свойств, потому что readonly-свойство со значением по умолчанию по существу совпадает с константой, и поэтому бесполезно.

>     <?php

>     class Test
>     {
>         // Error: Readonly property Test::$prop cannot have default value
>         public readonly int $prop = 42;
>     }

> Замечание:

> Конструкцией unset() нельзя уничтожить readonly-свойство после инициализации. Однако получится уничтожить readonly-свойство до инициализации из области видимости, в которой свойство объявили.

К изменениям относятся не только стандартные присваивания, следующие изменения тоже выбросят ошибку Error:

    <?php

    class Test
    {
        public function __construct(
            public readonly int $i = 0,
            public readonly array $ary = [],
        ) {}
    }

    $test = new Test();
    $test->i += 1;
    $test->i++;
    ++$test->i;
    $test->ary[] = 1;
    $test->ary[0][] = 1;
    unset($test->ary[0]);
    $ref =& $test->i;
    $test->i =& $ref;
    byRef($test->i);
    foreach ($test as &$prop);

При этом readonly-свойства не исключают внутреннюю изменчивость. Объекты и ресурсы, которые хранятся в readonly-свойствах, по-прежнему получится изменить внутри:

    <?php

    class Test
    {
        public function __construct(public readonly object $obj) {}
    }

    $test = new Test(new stdClass());

    // Правильное внутреннее изменение
    $test->obj->foo = 1;

    // Неправильное переопределение
    $test->obj = new stdClass();

Начиная с PHP 8.3.0 свойства, доступные только для чтения, разрешается инициализировать повторно при клонировании объекта через магический метод __clone().

Пример #6 Клонирование readonly-свойств

    <?php

    class Test1
    {
        public readonly ?string $prop;

        public function __clone()
        {
            $this->prop = null;
        }

        public function setProp(string $prop): void
        {
            $this->prop = $prop;
        }
    }

    $test1 = new Test1();
    $test1->setProp('foobar');

    $test2 = clone $test1;
    var_dump($test2->prop); // NULL

### Динамические свойства

При попытке присвоить несуществующее свойство объекту (object), PHP автоматически создаст такое свойство. Это динамически созданное свойство будет доступно только для этого экземпляра класса.

Внимание

С PHP 8.2.0 динамические свойства устарели. Вместо динамического присваивания свойства классу рекомендуют объявлять свойство. Для обработки произвольных имён свойств класс должен реализовать магические методы __get() и __set(). В крайнем случае класс помечают атрибутом `#[\AllowDynamicProperties]`.

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open