<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/language.oop5.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'ru',
  ),
  'this' => 
  array (
    0 => 'language.oop5.property-hooks.php',
    1 => 'Хуки свойств',
    2 => 'Хуки свойств',
  ),
  'up' => 
  array (
    0 => 'language.oop5.php',
    1 => 'Классы и объекты',
  ),
  'prev' => 
  array (
    0 => 'language.oop5.properties.php',
    1 => 'Свойства',
  ),
  'next' => 
  array (
    0 => 'language.oop5.constants.php',
    1 => 'Константы классов',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'ru',
    'path' => 'language/oop5/property-hooks.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="language.oop5.property-hooks" class="sect1">
 <h2 class="title">Хуки свойств</h2>

 <p class="simpara">
  Хуки свойств, которые в ряде других языков ещё называются «аксессорами свойств», представляют
  способ перехвата и переопределения поведения объектов при чтении и записи свойства.
  Функциональность хуков преследует две цели:
 </p>
 <ol type="1">
  <li class="listitem">
   <span class="simpara">
    Записывать и считывать значения свойств объектов напрямую, без методов получения и установки свойств,
    оставляя при этом открытым добавление дополнительного поведения в будущем.
    Это делает шаблонные геттеры и сеттеры ненужными,
    даже без хуков.
   </span>
  </li>
  <li class="listitem">
   <span class="simpara">
    Получать доступ к свойствам объекта
    без непосредственного хранения значений свойств.
   </span>
  </li>
 </ol>
 <p class="simpara">
  Для нестатических свойств доступны два хука: <code class="literal">get</code> и <code class="literal">set</code>.
  Хуки разрешают переопределять поведение чтения и записи свойства.
  Хуки доступны как для типизированных, так и для нетипизированных свойств.
 </p>
 <p class="simpara">
  Классы поддерживают «реальные» и «виртуальные» свойства.
  Реальное свойство — то, которое хранит действительное значение.
  Свойства без хуков — реальные.
  Виртуальное свойство — то, для которого объявили хуки и эти хуки не взаимодействуют с самим свойством.
  Хуки виртуальных свойств — практически то же самое, что и методы,
  и объект не занимает места в памяти для хранения значения такого свойства.
 </p>
 <p class="simpara">
  Хуки несовместимы с <code class="literal">readonly</code>-свойствами.
  Свойствам устанавливают <a href="language.oop5.visibility.php#language.oop5.visibility-members-aviz" class="link">асимметричную область видимости</a>,
  когда в дополнение к изменению поведения, которое вносят хуки <code class="literal">get</code> и <code class="literal">set</code>,
  требуется ограничить доступ к операциям чтения или записи.
 </p>

 <blockquote class="note"><p><strong class="note">Замечание</strong>: 
  <strong>Сведения о версии</strong><br />
  <span class="simpara">
   Хуки свойств были представлены в PHP 8.4.
  </span>
 </p></blockquote>

 <div class="sect2">
  <h3 class="title">Базовый синтаксис хуков</h3>
  <p class="simpara">
   Общий синтаксис объявления хука следующий.
  </p>
  <div class="example" id="example-1">
   <p><strong>Пример #1 Пример полной версии объявления хуков для свойств</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    private </span><span style="color: #0000BB">bool $modified </span><span style="color: #007700">= </span><span style="color: #0000BB">false</span><span style="color: #007700">;<br /><br />    public </span><span style="color: #0000BB">string $foo </span><span style="color: #007700">= </span><span style="color: #DD0000">'default value' </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">{<br />            if (</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified</span><span style="color: #007700">) {<br />                return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">. </span><span style="color: #DD0000">' (modified)'</span><span style="color: #007700">;<br />            }<br /><br />            return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo</span><span style="color: #007700">;<br />        }<br /><br />        </span><span style="color: #0000BB">set</span><span style="color: #007700">(</span><span style="color: #0000BB">string $value</span><span style="color: #007700">) {<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">= </span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />        }<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$example </span><span style="color: #007700">= new </span><span style="color: #0000BB">Example</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$example</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">= </span><span style="color: #DD0000">'changed'</span><span style="color: #007700">;<br />print </span><span style="color: #0000BB">$example</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo</span><span style="color: #007700">;</span></span></code></div>
   </div>

  </div>
  <p class="simpara">
   Объявление свойства <var class="varname">$foo</var> заканчивается фигурными скобками <code class="literal">{}</code>, а не точкой с запятой.
   Фигурные скобки указывают, что для свойства определили хуки.
   В примере определили оба хука — и <code class="literal">get</code>, и <code class="literal">set</code>,
   хотя разрешается определять отдельно один или другой.
   Для каждого хука определили тело, которое обозначается фигурными скобками <code class="literal">{}</code>.
   В теле записывают произвольный код.
  </p>
  <p class="simpara">
   Хук <code class="literal">set</code> дополнительно поддерживает объявление типа и названия входящего значения
   синтаксисом, аналогичным объявлению параметров в методах.
   Тип значения указывается либо с ограничением как у типа свойства,
   либо <a href="language.oop5.variance.php#language.oop5.variance.contravariance" class="link">контравариантным</a> к значению —
   с более широким, или слабым, ограничением.
   Например, для свойства с типом <span class="type"><a href="language.types.string.php" class="type string">string</a></span>
   в хуке <code class="literal">set</code> возможно определить параметр с типом
   <span class="type"><span class="type"><a href="language.types.string.php" class="type string">string</a></span>|<span class="type"><a href="class.stringable.php" class="type Stringable">Stringable</a></span></span>,
   но нельзя определить параметр с типом <span class="type"><a href="language.types.array.php" class="type array">array</a></span>, поскольку тип <span class="type"><a href="language.types.array.php" class="type array">array</a></span> не принадлежит ни самому строковому типу, ни надтипу строки.
  </p>
  <p class="simpara">
   В примере по крайней мере один хук ссылается на само свойство <code class="code">$this-&gt;foo</code>,
   поэтому свойство «реально».
   При вызове <code class="code">$example-&gt;foo = &#039;changed&#039;</code>
   строка вначале приводится к нижнему регистру, затем сохраняется как реальное значение.
   При чтении свойства сохранённое значение разрешается условно дополнить новым текстом.
  </p>
  <p class="simpara">
   Для обработки частых случаев предусмотрели ряд версий сокращенного синтаксиса.
  </p>
  <p class="simpara">
   Фигурные скобки <code class="literal">{}</code> опускают и заменяют стрелочным выражением,
   если хук <code class="literal">get</code> состоит из одного выражения.
  </p>
  <div class="example" id="example-2">
   <p><strong>Пример #2 Пример свойства с хуком get из одного выражения</strong></p>
   <div class="example-contents"><p>
    Этот пример эквивалентен предыдущему.
   </p></div>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    private </span><span style="color: #0000BB">bool $modified </span><span style="color: #007700">= </span><span style="color: #0000BB">false</span><span style="color: #007700">;<br /><br />    public </span><span style="color: #0000BB">string $foo </span><span style="color: #007700">= </span><span style="color: #DD0000">'default value' </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">. (</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified </span><span style="color: #007700">? </span><span style="color: #DD0000">' (modified)' </span><span style="color: #007700">: </span><span style="color: #DD0000">''</span><span style="color: #007700">);<br /><br />        </span><span style="color: #0000BB">set</span><span style="color: #007700">(</span><span style="color: #0000BB">string $value</span><span style="color: #007700">) {<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">= </span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />        }<br />    }<br />}</span></span></code></div>
   </div>

  </div>
  <p class="simpara">
   Параметр в объявлении хука разрешается опустить, если тип параметра в хуке <code class="literal">set</code> совпадает
   с типом свойства, что встречается часто.
   Тогда значению для установки автоматически присваивается имя <var class="varname">$value</var>.
  </p>
  <div class="example" id="example-3">
   <p><strong>Пример #3 Пример установки значения по умолчанию для свойства</strong></p>
   <div class="example-contents"><p>
    Этот пример эквивалентен предыдущему.
   </p></div>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    private </span><span style="color: #0000BB">bool $modified </span><span style="color: #007700">= </span><span style="color: #0000BB">false</span><span style="color: #007700">;<br /><br />    public </span><span style="color: #0000BB">string $foo </span><span style="color: #007700">= </span><span style="color: #DD0000">'default value' </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">. (</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified </span><span style="color: #007700">? </span><span style="color: #DD0000">' (modified)' </span><span style="color: #007700">: </span><span style="color: #DD0000">''</span><span style="color: #007700">);<br /><br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">{<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">= </span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />        }<br />    }<br />}</span></span></code></div>
   </div>

  </div>
  <p class="simpara">
   Хук <code class="literal">set</code> также можно упростить до выражения со стрелкой,
   если хук только устанавливает изменённую версию значения аргумента.
   Значение, которое вычислит выражение, установится как реальное значение свойства.
  </p>
  <div class="example" id="example-4">
   <p><strong>Пример #4 Пример установки значения свойства выражением в хуке set</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    private </span><span style="color: #0000BB">bool $modified </span><span style="color: #007700">= </span><span style="color: #0000BB">false</span><span style="color: #007700">;<br /><br />    public </span><span style="color: #0000BB">string $foo </span><span style="color: #007700">= </span><span style="color: #DD0000">'default value' </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">foo </span><span style="color: #007700">. (</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">modified </span><span style="color: #007700">? </span><span style="color: #DD0000">' (modified)' </span><span style="color: #007700">: </span><span style="color: #DD0000">''</span><span style="color: #007700">);<br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />    }<br />}</span></span></code></div>
   </div>

  </div>
  <p class="simpara">
   Этот пример не эквивалентен предыдущему,
   поскольку он не изменяет значение свойства <code class="code">$this-&gt;modified</code>, как предыдущий пример.
   В теле хука set пользуются версией синтаксиса с фигурными скобками, когда требуется указать больше одной инструкции.
  </p>
  <p class="simpara">
   В свойствах разрешается реализовывать ноль, один или оба хука в зависимости от ситуации.
   Сокращённые версии синтаксиса хуков не зависят одна от другой.
   Поэтому допустимы и короткий синтаксис хука get с длинным синтаксисом хука set,
   и короткий синтаксис хука set с явным типом параметра, и другие комбинации.
  </p>
  <p class="simpara">
   Пропуск хука <code class="literal">get</code> или <code class="literal">set</code> в реальном свойстве означает,
   что чтение или запись поведут себя по умолчанию.
  </p>
  <blockquote class="note"><p><strong class="note">Замечание</strong>: 
   <span class="simpara">
    PHP разрешает определять хуки
    <a href="language.oop5.decon.php#language.oop5.decon.constructor.promotion" class="link">при продвижении параметров конструктора до свойств класса</a>.
    При этом в конструктор потребуется передать значения, которые
    совпадают с типом свойства, независимо от типа,
    который разрешает хук <code class="literal">set</code>.
   </span>
   <span class="simpara">
    Посмотрим на следующий пример:
   </span>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">(<br />        public private(</span><span style="color: #0000BB">set</span><span style="color: #007700">) </span><span style="color: #0000BB">DateTimeInterface $created </span><span style="color: #007700">{<br />            </span><span style="color: #0000BB">set </span><span style="color: #007700">(</span><span style="color: #0000BB">string</span><span style="color: #007700">|</span><span style="color: #0000BB">DateTimeInterface $value</span><span style="color: #007700">) {<br />                if (</span><span style="color: #0000BB">is_string</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">)) {<br />                    </span><span style="color: #0000BB">$value </span><span style="color: #007700">= new </span><span style="color: #0000BB">DateTimeImmutable</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />                }<br /><br />                </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">created </span><span style="color: #007700">= </span><span style="color: #0000BB">$value</span><span style="color: #007700">;<br />            }<br />        },<br />    ) {}<br />}</span></span></code></div>
   </div>

   <span class="simpara">
    Внутренне движок разберёт этот код так:
   </span>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    public private(</span><span style="color: #0000BB">set</span><span style="color: #007700">) </span><span style="color: #0000BB">DateTimeInterface $created </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">(</span><span style="color: #0000BB">string</span><span style="color: #007700">|</span><span style="color: #0000BB">DateTimeInterface $value</span><span style="color: #007700">) {<br />            if (</span><span style="color: #0000BB">is_string</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">)) {<br />                </span><span style="color: #0000BB">$value </span><span style="color: #007700">= new </span><span style="color: #0000BB">DateTimeImmutable</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />            }<br /><br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">created </span><span style="color: #007700">= </span><span style="color: #0000BB">$value</span><span style="color: #007700">;<br />        }<br />    }<br /><br />    public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">(<br />        </span><span style="color: #0000BB">DateTimeInterface $created</span><span style="color: #007700">,<br />    ) {<br />        </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">created </span><span style="color: #007700">= </span><span style="color: #0000BB">$created</span><span style="color: #007700">;<br />    }<br />}</span></span></code></div>
   </div>

   <span class="simpara">
    Установка свойства в классе, вне передачи аргументов в конструктор,
    разрешит значения с типом <span class="type"><a href="language.types.string.php" class="type string">string</a></span> или <span class="interfacename"><a href="class.datetimeinterface.php" class="interfacename">DateTimeInterface</a></span>,
    но конструктор разрешит только тип <span class="interfacename"><a href="class.datetimeinterface.php" class="interfacename">DateTimeInterface</a></span>.
    Причина этого состоит в том, что тип <span class="interfacename"><a href="class.datetimeinterface.php" class="interfacename">DateTimeInterface</a></span>, который определяет свойство,
    внутри сигнатуры конструктора определяет тип параметра, независимо от того,
    что разрешает хук <code class="literal">set</code>.
   </span>
   <span class="simpara">
    Нельзя продвигать параметры конструктора до свойств класса,
    если от конструктора требуется такое поведение.
   </span>
  </p></blockquote>
 </div>
 <div class="sect2" id="language.oop5.property-hooks.virtual">
  <h3 class="title">Виртуальные свойства</h3>
  <p class="simpara">
   Виртуальными называются свойства без реальных значений.
   Свойство станет виртуальным, если ни хук <code class="literal">get</code>,
   ни хук <code class="literal">set</code> не ссылаются на само свойство точным синтаксисом.
   Свойство с именем <code class="code">$foo</code>, хук которого содержит ссылку на само свойство <code class="code">$this-&gt;foo</code>, — реальное.
   Но свойство в следующем примере не относится к реальным и вызовет ошибку:
  </p>
  <div class="example" id="example-5">
   <p><strong>Пример #5 Пример недопустимого виртуального свойства</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">string $foo </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">{<br />            </span><span style="color: #0000BB">$temp </span><span style="color: #007700">= </span><span style="color: #0000BB">__PROPERTY__</span><span style="color: #007700">;<br />            return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">$temp</span><span style="color: #007700">; </span><span style="color: #FF8000">// Инструкция return не ссылается на реальное свойство $this-&gt;foo,<br />                                 // поэтому это не считается<br />        </span><span style="color: #007700">}<br />    }<br />}</span></span></code></div>
   </div>

  </div>
  <p class="simpara">
   Попытка выполнить с виртуальным свойством операцию, для которой не объявили хук,
   вызовет ошибку, поскольку поведение по умолчанию для такой операции останется неопределённым.
   Виртуальные свойства не занимают места в памяти объекта.
   Виртуальные свойства помогают создавать «производные» свойства
   наподобие комбинации значений двух других свойств.
  </p>
  <div class="example" id="example-6">
   <p><strong>Пример #6 Пример виртуального свойства</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Rectangle<br /></span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">// Виртуальное свойство<br />    </span><span style="color: #007700">public </span><span style="color: #0000BB">int $area </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">h </span><span style="color: #007700">* </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">w</span><span style="color: #007700">;<br />    }<br /><br />    public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">(public </span><span style="color: #0000BB">int $h</span><span style="color: #007700">, public </span><span style="color: #0000BB">int $w</span><span style="color: #007700">) {}<br />}<br /><br /></span><span style="color: #0000BB">$s </span><span style="color: #007700">= new </span><span style="color: #0000BB">Rectangle</span><span style="color: #007700">(</span><span style="color: #0000BB">4</span><span style="color: #007700">, </span><span style="color: #0000BB">5</span><span style="color: #007700">);<br />print </span><span style="color: #0000BB">$s</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">area</span><span style="color: #007700">; </span><span style="color: #FF8000">// Выводит 20<br /></span><span style="color: #0000BB">$s</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">area </span><span style="color: #007700">= </span><span style="color: #0000BB">30</span><span style="color: #007700">; </span><span style="color: #FF8000">// Ошибка, поскольку для свойства не определили комбинацию записи</span></span></code></div>
   </div>

  </div>
  <p class="simpara">
   Для виртуальных свойств поддерживается определение обоих хуков: <code class="literal">get</code> и <code class="literal">set</code>.
  </p>
 </div>
 <div class="sect2">
  <h3 class="title">Об области видимости</h3>
  <p class="simpara">
   Хуки действуют в области видимости модифицируемого объекта.
   Поэтому хукам доступны открытые, защищённые и закрытые методы и свойства объекта,
   включая свойства с хуками.
   Хуки свойств срабатывают при каждом обращении к свойству, даже при обращении из хука другого свойства.
  </p>
  <p class="simpara">
   За счёт доступа к членам объекта и срабатывания при каждой операции чтения или записи
   хуки поддерживают не только тривиальную логику, но и, если потребуется, вызов методов произвольной сложности.
  </p>
  <div class="example" id="example-7">
   <p><strong>Пример #7 Пример вызова метода из хука</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Person<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">string $phone </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sanitizePhone</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />    }<br /><br />    private function </span><span style="color: #0000BB">sanitizePhone</span><span style="color: #007700">(</span><span style="color: #0000BB">string $value</span><span style="color: #007700">): </span><span style="color: #0000BB">string<br />    </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">$value </span><span style="color: #007700">= </span><span style="color: #0000BB">ltrim</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">, </span><span style="color: #DD0000">'+'</span><span style="color: #007700">);<br />        </span><span style="color: #0000BB">$value </span><span style="color: #007700">= </span><span style="color: #0000BB">ltrim</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">, </span><span style="color: #DD0000">'1'</span><span style="color: #007700">);<br /><br />        if (!</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(</span><span style="color: #DD0000">'/\d\d\d\-\d\d\d\-\d\d\d\d/'</span><span style="color: #007700">, </span><span style="color: #0000BB">$value</span><span style="color: #007700">)) {<br />            throw new </span><span style="color: #0000BB">\InvalidArgumentException</span><span style="color: #007700">();<br />        }<br /><br />        return </span><span style="color: #0000BB">$value</span><span style="color: #007700">;<br />    }<br />}</span></span></code></div>
   </div>

  </div>
 </div>
 <div class="sect2">
  <h3 class="title">Ссылки</h3>
  <p class="simpara">
   Поскольку хуки перехватывают процесс чтения и записи свойств,
   они вызывают проблемы при получении ссылки на свойство или при косвенной модификации,
   например, <code class="code">$this-&gt;arrayProp[&#039;key&#039;] = &#039;value&#039;;</code>.
   Это связано с тем, что попытка изменения значения по ссылке обойдет хук set,
   если его определили.
  </p>
  <p class="simpara">
   В редких случаях, когда требуется получить ссылку на свойство,
   для которого определили хуки, перед хуком <code class="literal">get</code> разрешается добавлять префикс <code class="literal">&amp;</code>,
   чтобы заставить хук возвращать значение по ссылке.
   Определение <code class="literal">get</code> и <code class="literal">&amp;get</code>
   для одного и того же свойства вызовет синтаксическую ошибку.
  </p>
  <p class="simpara">
   Нельзя определять одновременно хуки <code class="literal">&amp;get</code> и <code class="literal">set</code> для реального свойства.
   Как уже отмечалось, запись в значение, которое возвращается по ссылке, обойдет хук <code class="literal">set</code>.
   Виртуальные свойства не хранят обязательного общего значения, которое хуки разделяют между собой,
   поэтому хуки для чтения свойства разрешается определять с возвратом по значению или по ссылке.
  </p>
  <p class="simpara">
   Значения в индекс свойства-массива также неявно записываются по ссылке.
   Поэтому запись в свойство с реальным массивом и хуками разрешается,
   если только в свойстве определили единственный хук <code class="literal">&amp;get</code>.
   В виртуальном свойстве запись в массив, который возвращает хук <code class="literal">get</code>
   или <code class="literal">&amp;get</code>, возможна, но повлияет ли это
   на объект, зависит от реализации хука.
  </p>
  <p class="simpara">
   Перезапись самого свойства массива возможна и ведёт себя как и другие свойства.
   Только работа с элементами массива требует осторожности.
  </p>
 </div>
 <div class="sect2">
  <h3 class="title">Наследование</h3>
  <div class="sect3">
   <h4 class="title">Окончательные хуки</h4>
   <p class="simpara">
    Хуки разрешается также объявлять окончательными через ключевое слово <a href="language.oop5.final.php" class="link">final</a>,
    тогда хуки нельзя переопределять.
   </p>
   <div class="example" id="example-8">
    <p><strong>Пример #8 Пример с окончательными хуками</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">User<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">string $username </span><span style="color: #007700">{<br />        final </span><span style="color: #0000BB">set </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Manager </span><span style="color: #007700">extends </span><span style="color: #0000BB">User<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">string $username </span><span style="color: #007700">{<br />        </span><span style="color: #FF8000">// Это возможно<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">strtoupper</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">username</span><span style="color: #007700">);<br /><br />        </span><span style="color: #FF8000">// Но это недопустимо, поскольку хук set окончателен в родительском элементе<br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">strtoupper</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />    }<br />}</span></span></code></div>
    </div>

   </div>
   <p class="simpara">
    Свойство тоже возможно объявить окончательным через ключевое слово <a href="language.oop5.final.php" class="link">final</a>.
    Окончательное свойство нельзя повторно объявлять в дочернем классе,
    что исключает изменение хуков или ослабление доступа к операциям хуков.
   </p>
   <p class="simpara">
    Объявление окончательных хуков для окончательных свойств избыточно,
    и без предупреждения проигнорируется.
    Это то же поведение, что и у окончательных методов.
   </p>
   <p class="simpara">
    Подклассы поддерживают определение своих хуков и переопределение отдельных хуков родительских свойств.
    В подклассах хуки переопределяют путём переопределения свойства только с конкретными хуками.
    Дочерние классы поддерживают также добавление свойствам хуков, которые не определили в родительском классе.
    Практически, правила переопределения хуков аналогичны правилам переопределения методов.
   </p>
   <div class="example" id="example-9">
    <p><strong>Пример #9 Наследование хуков</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Point<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">int $x</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">int $y</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">PositivePoint </span><span style="color: #007700">extends </span><span style="color: #0000BB">Point<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">int $x </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">{<br />            if (</span><span style="color: #0000BB">$value </span><span style="color: #007700">&lt; </span><span style="color: #0000BB">0</span><span style="color: #007700">) {<br />                throw new </span><span style="color: #0000BB">\InvalidArgumentException</span><span style="color: #007700">(</span><span style="color: #DD0000">'Число слишком маленькое'</span><span style="color: #007700">);<br />            }<br /><br />            </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">x </span><span style="color: #007700">= </span><span style="color: #0000BB">$value</span><span style="color: #007700">;<br />        }<br />    }<br />}</span></span></code></div>
    </div>

   </div>
   <p class="simpara">
    Каждый хук переопределяет родительские реализации независимо друг от друга.
    Значения по умолчанию, которые установили для свойств, удалятся и потребуется объявить значение заново,
    если дочерний класс добавляет хуки.
    Это согласуется с тем, как наследование работает в свойствах без хуков.
   </p>
  </div>
  <div class="sect3">
   <h4 class="title">Доступ к родительским хукам</h4>
   <p class="simpara">
    Хук в дочернем классе получает доступ к свойству родительского класса
    через ключевое слово <code class="code">parent::$prop</code>, за которым следует хук, к которому требуется доступ.
    Например, <code class="code">parent::$propName::get()</code>.
    Это читается как «получить доступ к свойству <var class="varname">prop</var>, которое определили
    в родительском классе, а затем выполнить операцию get, или операцию set, в зависимости от ситуации.
   </p>
   <p class="simpara">
    Хук родительского класса игнорируется, если только доступ к родительскому хуку не выполняется непосредственно.
    Такое поведение соответствует работе методов.
    Синтаксис обращения к родительскому хуку также открывает доступ к хранилищу родительского класса,
    если родительский класс содержит такое хранилище.
    Чтение или запись поведут себя по умолчанию, если хук для родительского свойства не определили.
    Хукам нельзя получать доступ к другим хукам, за исключением своих хуков в родительских классах.
   </p>
   <p class="simpara">
    Проблема предыдущего примера состоит в том, что дочерний класс проигнорирует хук,
    который добавят в родительском.
    Модификация примера разрешит добавить хук <code class="literal">set</code>
    в классе <code class="literal">Point</code> в будущем.
   </p>
   <div class="example" id="example-10">
    <p><strong>Пример #10 Доступ к родительскому хуку (set)</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Point<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">int $x</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">int $y</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">PositivePoint </span><span style="color: #007700">extends </span><span style="color: #0000BB">Point<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">int $x </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">set </span><span style="color: #007700">{<br />            if (</span><span style="color: #0000BB">$value </span><span style="color: #007700">&lt; </span><span style="color: #0000BB">0</span><span style="color: #007700">) {<br />                throw new </span><span style="color: #0000BB">\InvalidArgumentException</span><span style="color: #007700">(</span><span style="color: #DD0000">'Число слишком маленькое'</span><span style="color: #007700">);<br />            }<br /><br />            </span><span style="color: #0000BB">parent</span><span style="color: #007700">::</span><span style="color: #0000BB">$x</span><span style="color: #007700">::</span><span style="color: #0000BB">set</span><span style="color: #007700">(</span><span style="color: #0000BB">$value</span><span style="color: #007700">);<br />        }<br />    }<br />}</span></span></code></div>
    </div>

   </div>
   <p class="simpara">
    Пример переопределения только хука get:
   </p>
   <div class="example" id="example-11">
    <p><strong>Пример #11 Доступ к родительскому хуку (get)</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Strings<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">string $val</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">CaseFoldingStrings </span><span style="color: #007700">extends </span><span style="color: #0000BB">Strings<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">bool $uppercase </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">;<br /><br />    public </span><span style="color: #0000BB">string $val </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">get </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">uppercase<br />            </span><span style="color: #007700">? </span><span style="color: #0000BB">strtoupper</span><span style="color: #007700">(</span><span style="color: #0000BB">parent</span><span style="color: #007700">::</span><span style="color: #0000BB">$val</span><span style="color: #007700">::</span><span style="color: #0000BB">get</span><span style="color: #007700">())<br />            : </span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(</span><span style="color: #0000BB">parent</span><span style="color: #007700">::</span><span style="color: #0000BB">$val</span><span style="color: #007700">::</span><span style="color: #0000BB">get</span><span style="color: #007700">())<br />        ;<br />    }<br />}</span></span></code></div>
    </div>

   </div>
  </div>
 </div>
 <div class="sect2">
  <h3 class="title">Сериализация</h3>
  <p class="simpara">
   В PHP предусмотрели ряд способов сериализовать объект в производственной среде
   или в целях отладки.
   Поведение хуков зависит от сценария.
   В одних случаях берётся необработанное реальное значение свойства,
   а хуки обходятся.
   В других — свойство считывается или записывается «через» хук,
   как и другие стандартные операции чтения и записи.
  </p>
  <ul class="simplelist">
   <li>Функция <span class="function"><a href="function.var-dump.php" class="function">var_dump()</a></span>: берёт необработанное значение</li>
   <li>Функция <span class="function"><a href="function.serialize.php" class="function">serialize()</a></span>: берёт необработанное значение</li>
   <li>Функция <span class="function"><a href="function.unserialize.php" class="function">unserialize()</a></span>: берёт необработанное значение</li>
   <li>
     Магические методы <a href="language.oop5.magic.php#object.serialize" class="link">__serialize()</a>
     и <a href="language.oop5.magic.php#object.unserialize" class="link">__unserialize()</a>:
     реализуют пользовательскую логику с хуками чтения или записи
   </li>
   <li>Приведение массива: берёт необработанное значение</li>
   <li>Функция <span class="function"><a href="function.var-export.php" class="function">var_export()</a></span>: задействует хук get</li>
   <li>Функция <span class="function"><a href="function.json-encode.php" class="function">json_encode()</a></span>: задействует хук get</li>
   <li>Интерфейс JsonSerializable: реализует пользовательскую логику с хуком get</li>
   <li>Функция <span class="function"><a href="function.get-object-vars.php" class="function">get_object_vars()</a></span>: задействует хук get</li>
   <li>Функция <span class="function"><a href="function.get-mangled-object-vars.php" class="function">get_mangled_object_vars()</a></span>: берёт необработанное значение</li>
  </ul>
 </div>
</div><?php manual_footer($setup); ?>