<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/migration81.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'ru',
  ),
  'this' => 
  array (
    0 => 'migration81.incompatible.php',
    1 => 'Изменения, которые ломают обратную совместимость',
    2 => 'Изменения, которые ломают обратную совместимость',
  ),
  'up' => 
  array (
    0 => 'migration81.php',
    1 => 'Миграция с PHP 8.0.x на PHP 8.1.x',
  ),
  'prev' => 
  array (
    0 => 'migration81.constants.php',
    1 => 'Новые глобальные константы',
  ),
  'next' => 
  array (
    0 => 'migration81.deprecated.php',
    1 => 'Устаревшая функциональность',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'ru',
    'path' => 'appendices/migration81/incompatible.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="migration81.incompatible" class="sect1">
 <h2 class="title">Изменения, которые ломают обратную совместимость</h2>

 <div class="sect2" id="migration81.incompatible.core">
  <h3 class="title">Ядро PHP</h3>

  <div class="sect3" id="migration81.incompatible.core.globals-access">
   <h4 class="title">Ограничения доступа к суперглобальной переменной $GLOBALS</h4>

   <p class="para">
    Доступ к массиву <var class="varname"><a href="reserved.variables.globals.php" class="classname">$GLOBALS</a></var> теперь имеет
    ряд ограничений.
    Чтение и запись отдельных элементов массива,
    как например, <code class="code">$GLOBALS[&#039;var&#039;]</code>, по-прежнему работает.
    Чтение всего массива <var class="varname"><a href="reserved.variables.globals.php" class="classname">$GLOBALS</a></var>
    также поддерживается.
    Однако операции, связанные с изменением всего <var class="varname"><a href="reserved.variables.globals.php" class="classname">$GLOBALS</a></var>, запрещены.
    Например, <code class="code">array_pop($GLOBALS)</code> приведёт к ошибке.
   </p>
  </div>

  <div class="sect3" id="migration81.incompatible.core.static-variable-inheritance">
   <h4 class="title">
    Использование <span class="modifier">static</span>-переменных в унаследованных методах
   </h4>

   <p class="para">
    Когда метод, использующий статические переменные, наследуется (но не переопределяется),
    унаследованный метод теперь будет использовать статические переменные совместно с родительским методом.
    <div class="informalexample">
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br />    public static function </span><span style="color: #0000BB">counter</span><span style="color: #007700">() {<br />        static </span><span style="color: #0000BB">$counter </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">$counter</span><span style="color: #007700">++;<br />        return </span><span style="color: #0000BB">$counter</span><span style="color: #007700">;<br />    }<br />}<br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A </span><span style="color: #007700">{}<br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">counter</span><span style="color: #007700">()); </span><span style="color: #FF8000">// int(1)<br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">counter</span><span style="color: #007700">()); </span><span style="color: #FF8000">// int(2)<br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">counter</span><span style="color: #007700">()); </span><span style="color: #FF8000">// int(3), ранее было int(1)<br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">counter</span><span style="color: #007700">()); </span><span style="color: #FF8000">// int(4), ранее было int(2)<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

    </div>

    Это означает, что статические переменные в методах теперь ведут себя так же,
    как статические свойства.
   </p>
  </div>

  <div class="sect3" id="migration81.incompatible.core.optional-before-required">
   <h4 class="title">Необязательные параметры, указанные перед обязательными параметрами</h4>
   <p class="para">
    <a href="functions.arguments.php#functions.arguments.default" class="link">Необязательный параметр</a>,
    указанный перед обязательными параметрами,
    теперь всегда обрабатывается как обязательный, даже при вызове с использованием
    <a href="functions.arguments.php#functions.named-arguments" class="link">именованных аргументов</a>.
    Начиная с PHP 8.0.0, но до PHP 8.1.0, приведённый ниже код выдаёт предупреждение об устаревании определения,
    но успешно выполняется при вызове. Начиная с PHP 8.1.0, выдаётся ошибка класса
    <span class="classname"><a href="class.argumentcounterror.php" class="classname">ArgumentCountError</a></span>, как это было бы при вызове с позиционными аргументами.
    <div class="informalexample">
     <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">makeyogurt</span><span style="color: #007700">(</span><span style="color: #0000BB">$container </span><span style="color: #007700">= </span><span style="color: #DD0000">"миску"</span><span style="color: #007700">, </span><span style="color: #0000BB">$flavour</span><span style="color: #007700">)<br />{<br />    return </span><span style="color: #DD0000">"Готовим </span><span style="color: #0000BB">$container</span><span style="color: #DD0000"> с </span><span style="color: #0000BB">$flavour</span><span style="color: #DD0000"> йогуртом.\n"</span><span style="color: #007700">;<br />}<br />try<br />{<br />    echo </span><span style="color: #0000BB">makeyogurt</span><span style="color: #007700">(</span><span style="color: #0000BB">flavour</span><span style="color: #007700">: </span><span style="color: #DD0000">"малиновым"</span><span style="color: #007700">);<br />}<br />catch (</span><span style="color: #0000BB">Error $e</span><span style="color: #007700">)<br />{<br />    echo </span><span style="color: #0000BB">get_class</span><span style="color: #007700">(</span><span style="color: #0000BB">$e</span><span style="color: #007700">), </span><span style="color: #DD0000">' - '</span><span style="color: #007700">, </span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMessage</span><span style="color: #007700">(), </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

     
<p class="para">
 Результат выполнения приведённого примера в PHP 8.0:
</p>

     <div class="example-contents screen">
<div class="cdata"><pre>
Deprecated: Required parameter $flavour follows optional parameter $container
 in example.php on line 3
Готовим миску с малиновым йогуртом.
</pre></div>
     </div>
     
<p class="para">
 Результат выполнения приведённого примера в PHP 8.1:
</p>

     <div class="example-contents screen">
<div class="cdata"><pre>
Deprecated: Optional parameter $container declared before required parameter
 $flavour is implicitly treated as a required parameter in example.php on line 3
ArgumentCountError - makeyogurt(): Argument #1 ($container) not passed
</pre></div>
     </div>
    </div>
   </p>
   <p class="para">
    Обратите внимание, что значение по умолчанию <strong><code><a href="reserved.constants.php#constant.null">null</a></code></strong> может использоваться перед обязательными параметрами
    для указания <a href="language.types.declarations.php#language.types.declarations.nullable" class="link">типа, допускающего значение null</a>,
    но этот параметр всё равно будет обязательным.
   </p>
  </div>

  <div class="sect3" id="migration81.incompatible.core.type-compatibility-internal">
   <h4 class="title">Совместимость типа возвращаемого значения с внутренними классами</h4>

   <p class="para">
    Большинство неокончательных внутренних методов теперь требуют переопределяющих методов
    для объявления совместимого возвращаемого типа, в противном случае во время проверки
    наследования выдаётся уведомление об устаревании возможности.
    В случае, если тип возвращаемого значения не может быть объявлен для метода
    переопределения из-за проблем совместимости версий PHP, можно добавить атрибут
    <span class="classname"><a href="class.returntypewillchange.php" class="classname">ReturnTypeWillChange</a></span>, чтобы заглушить уведомление об устаревании.
   </p>
  </div>

  <div class="sect3" id="migration81.incompatible.core.new-keywords">
   <h4 class="title">Новые ключевые слова</h4>
   <p class="para">
    <code class="literal">readonly</code> теперь является ключевым словом.
    Однако его можно использовать как имя функции.
   </p>
   <p class="para">
    <code class="literal">never</code> теперь является зарезервированным словом,
    поэтому его нельзя использовать для названия класса, интерфейса или трейта,
    а также запрещено использовать в пространствах имён.
   </p>
  </div>

 </div>

 <div class="sect2" id="migration81.incompatible.resource2object">
  <h3 class="title">Переход от ресурсов к объектам</h3>

  <p class="para">
   Несколько ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>) теперь представлены как объекты (<span class="type"><a href="language.types.object.php" class="type object">object</a></span>).
   Проверки возвращаемого значения с использованием функции <span class="function"><a href="function.is-resource.php" class="function">is_resource()</a></span>
   следует заменить проверками на <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>.
  </p>
  <ul class="itemizedlist">
   <li class="listitem">
    <p class="para">
     Функции <a href="book.fileinfo.php" class="link">FileInfo</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.finfo.php" class="classname">finfo</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">fileinfo</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.ftp.php" class="link">FTP</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.ftp-connection.php" class="classname">FTP\Connection</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">ftp</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.imap.php" class="link">IMAP</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.imap-connection.php" class="classname">IMAP\Connection</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">imap</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     The <a href="book.ldap.php" class="link">LDAP</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.ldap-connection.php" class="classname">LDAP\Connection</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">ldap link</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.ldap.php" class="link">LDAP</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.ldap-result.php" class="classname">LDAP\Result</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">ldap result</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.ldap.php" class="link">LDAP</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.ldap-result-entry.php" class="classname">LDAP\ResultEntry</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">ldap result entry</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.pgsql.php" class="link">PgSQL</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.pgsql-connection.php" class="classname">PgSql\Connection</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">pgsql link</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.pgsql.php" class="link">PgSQL</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.pgsql-result.php" class="classname">PgSql\Result</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">pgsql result</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.pgsql.php" class="link">PgSQL</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.pgsql-lob.php" class="classname">PgSql\Lob</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">pgsql large object</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.pspell.php" class="link">PSpell</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.pspell-dictionary.php" class="classname">PSpell\Dictionary</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">pspell</code>.
    </p>
   </li>
   <li class="listitem">
    <p class="para">
     Функции <a href="book.pspell.php" class="link">PSpell</a> теперь принимают и возвращают
     объекты <span class="classname"><a href="class.pspell-config.php" class="classname">PSpell\Config</a></span> вместо ресурсов (<span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span>)
     <code class="literal">pspell config</code>.
    </p>
   </li>
  </ul>
 </div>

 <div class="sect2" id="migration81.incompatible.mysqli">
  <h3 class="title">MySQLi</h3>

  <p class="para">
   Функции <span class="function"><a href="mysqli-result.fetch-fields.php" class="function">mysqli_fetch_fields()</a></span> и
   <span class="function"><a href="mysqli-result.fetch-field-direct.php" class="function">mysqli_fetch_field_direct()</a></span> теперь всегда возвращают
   <code class="literal">0</code> в свойстве <span class="property">max_length</span>.
   Это значение можно вычислить, перебирая набор результатов
   и выбирая максимальную длину. Такой алгоритм раньше использовал PHP.
  </p>

  <p class="para">
   Опция <strong><code><a href="mysqli.constants.php#constant.mysqli-stmt-attr-update-max-length">MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH</a></code></strong>
   больше не имеет смысла.
  </p>

  <p class="para">
   Опция <strong><code><a href="mysqli.constants.php#constant.mysqli-store-result-copy-data">MYSQLI_STORE_RESULT_COPY_DATA</a></code></strong>
   больше не имеет смысла. Передача какого-либо значения в параметр
   <code class="parameter">mode</code> метода
   <span class="methodname"><a href="mysqli.store-result.php" class="methodname">mysqli::store_result()</a></span> больше не имеет смысла.
  </p>

  <p class="para">
   <span class="methodname"><a href="mysqli.construct.php" class="methodname">mysqli::connect()</a></span> теперь возвращает <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong> вместо <strong><code><a href="reserved.constants.php#constant.null">null</a></code></strong> в случае успешного выполнения.
  </p>

  <p class="para">
   Режим обработки ошибок по умолчанию был изменён с &quot;silent&quot; на &quot;exceptions&quot;.
   Смотрите страницу <a href="mysqli-driver.report-mode.php" class="link">Режимы обработки ошибок MySQLi</a>
   для получения дополнительных сведений о том, что это влечёт за собой
   и о том, как явно установить этот атрибут.
   Чтобы восстановить предыдущее поведение, используйте:
   <code class="code">mysqli_report(MYSQLI_REPORT_OFF);</code>
  </p>

  <p class="para">
   Классы, расширяющие <span class="methodname"><a href="mysqli-stmt.execute.php" class="methodname">mysqli_stmt::execute()</a></span>,
   теперь должны указывать дополнительный необязательный параметр.
  </p>
 </div>

 <div class="sect2" id="migration81.incompatible.mysqlnd">
  <h3 class="title">MySQLnd</h3>

  <p class="para">
   INI-директива <a href="mysqlnd.config.php#ini.mysqlnd.fetch_data_copy" class="link">mysqlnd.fetch_data_copy</a>
   была удалена.
   Это не должно приводить к видимым для пользователя изменениям в поведении.
  </p>
 </div>

 <div class="sect2" id="migration81.incompatible.openssl">
  <h3 class="title">OpenSSL</h3>

  <p class="para">
   Секретные ключи EC теперь будут экспортироваться в формате <abbr title="Public Key Cryptography Standards">PKCS</abbr>#8,
   а не в традиционном формате, как и все другие ключи.
  </p>
  <p class="para">
   Функции <span class="function"><a href="function.openssl-pkcs7-encrypt.php" class="function">openssl_pkcs7_encrypt()</a></span> и
   <span class="function"><a href="function.openssl-cms-encrypt.php" class="function">openssl_cms_encrypt()</a></span> теперь по умолчанию используют шифр AES-128-CBC, а не RC2-40.
   Шифр RC2-40 считается небезопасным и не включён по умолчанию в OpenSSL 3.
  </p>
 </div>

 <div class="sect2" id="migration81.incompatible.pdo">
  <h3 class="title">Объекты данных PHP</h3>

  <p class="para">
   Атрибут <strong><code><a href="pdo.constants.php#pdo.constants.attr-stringify-fetches">PDO::ATTR_STRINGIFY_FETCHES</a></code></strong> теперь преобразовывает логические значения (<span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span>)
   в <code class="literal">&quot;0&quot;</code> или <code class="literal">&quot;1&quot;</code>.
   Ранее логические значения (<span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span>) не были строковыми.
  </p>
  <p class="para">
   Вызов <span class="methodname"><a href="pdostatement.bindcolumn.php" class="methodname">PDOStatement::bindColumn()</a></span> с <strong><code><a href="pdo.constants.php#pdo.constants.param-lob">PDO::PARAM_LOB</a></code></strong>
   теперь будет постоянно связывать результат потока, если <strong><code><a href="pdo.constants.php#pdo.constants.attr-stringify-fetches">PDO::ATTR_STRINGIFY_FETCHES</a></code></strong> не включён.
   Раньше результатом был либо поток, либо строка в зависимости от используемого драйвера базы данных
   и времени выполнения привязки.
  </p>

  <div class="sect3" id="migration81.incompatible.pdo.mysql">
   <h4 class="title">Драйвер MySQL</h4>

   <p class="para">
    Целые числа и числа с плавающей запятой в наборах результатов
    теперь будут возвращаться с использованием собственных типов PHP вместо
    строк (<span class="type"><a href="language.types.string.php" class="type string">string</a></span>) при использовании эмулированных подготовленных операторов.
    Это соответствует поведению собственных подготовленных операторов.
    Предыдущее поведение можно восстановить,
    включив опцию <strong><code><a href="pdo.constants.php#pdo.constants.attr-stringify-fetches">PDO::ATTR_STRINGIFY_FETCHES</a></code></strong>.
   </p>
  </div>

  <div class="sect3" id="migration81.incompatible.pdo.sqlite">
   <h4 class="title">Драйвер SQLite</h4>

   <p class="para">
    Целые числа и числа с плавающей запятой в наборах результатов
    теперь будут возвращаться с использованием собственных типов PHP.
    Предыдущее поведение можно восстановить,
    включив опцию <strong><code><a href="pdo.constants.php#pdo.constants.attr-stringify-fetches">PDO::ATTR_STRINGIFY_FETCHES</a></code></strong>.
   </p>
  </div>
 </div>

 <div class="sect2" id="migration81.incompatible.phar">
  <h3 class="title">Phar</h3>

  <p class="para">
   Чтобы соответствовать интерфейсу <span class="interfacename"><a href="class.arrayaccess.php" class="interfacename">ArrayAccess</a></span>,
   <span class="methodname"><a href="phar.offsetunset.php" class="methodname">Phar::offsetUnset()</a></span> и <span class="methodname"><a href="phardata.offsetunset.php" class="methodname">PharData::offsetUnset()</a></span>
   больше не возвращают логическое значение (<span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span>).
  </p>
 </div>

 <div class="sect2" id="migration81.incompatible.standard">
  <h3 class="title">Стандартные функции</h3>

  <p class="para">
   <span class="function"><a href="function.version-compare.php" class="function">version_compare()</a></span> больше не принимает недокументированные сокращения операторов.
  </p>

  <p class="para">
   Функции <span class="function"><a href="function.htmlspecialchars.php" class="function">htmlspecialchars()</a></span>,
   <span class="function"><a href="function.htmlentities.php" class="function">htmlentities()</a></span>,
   <span class="function"><a href="function.htmlspecialchars-decode.php" class="function">htmlspecialchars_decode()</a></span>,
   <span class="function"><a href="function.html-entity-decode.php" class="function">html_entity_decode()</a></span>
   и <span class="function"><a href="function.get-html-translation-table.php" class="function">get_html_translation_table()</a></span>
   теперь по умолчанию используют <code class="literal">ENT_QUOTES | ENT_SUBSTITUTE</code> вместо
   <strong><code><a href="string.constants.php#constant.ent-compat">ENT_COMPAT</a></code></strong>.
   Это означает, что теперь <code class="literal">&#039;</code> экранируется в <code class="literal">&amp;#039;</code>.
   Кроме того, в случае неправильного UTF-8 вместо пустой строки будет возвращён
   замещающий символ Unicode.
  </p>

  <p class="para">
   <span class="function"><a href="function.debug-zval-dump.php" class="function">debug_zval_dump()</a></span> теперь выводит refcount ссылочных
   оболочек с их refcount, вместо того, чтобы просто добавлять
   <code class="literal">&amp;</code> к значению.
   Это более точно моделирует эталонное представление, начиная с PHP 7.0.
  </p>

  <p class="para">
   <span class="function"><a href="function.debug-zval-dump.php" class="function">debug_zval_dump()</a></span> теперь выводит <code class="literal">interned</code>
   вместо фиктивного refcount для интернированных строк и неизменяемых массивов.
  </p>
 </div>

 <div class="sect2" id="migration81.incompatible.spl">
  <h3 class="title">Стандартная библиотека PHP (SPL)</h3>

  <p class="para">
   <span class="classname"><a href="class.splfixedarray.php" class="classname">SplFixedArray</a></span> теперь будет закодирован в JSON как массив (<span class="type"><a href="language.types.array.php" class="type array">array</a></span>).
  </p>
 </div>

</div><?php manual_footer($setup); ?>