БлогNot. Миграция с PHP5 на PHP7 и PHP8: что чаще всего приходится править в исходниках

Миграция с PHP5 на PHP7 и PHP8: что чаще всего приходится править в исходниках

Если не считать необходимого теперь перехода с MySQL на MySQLi и борьбы с Warning: A non-numeric value encountered, есть ещё несколько типовых проблем при миграции скриптов с PHP 5.X (особенно если исходная версия ниже 5.3) на PHP 7.3 - 7.4, а позднее и на PHP 8. Попробую приспособить для описания решений эту заметку, если ещё всплывёт подобное.

Для проверки фрагментов кода предполагалось, что в его начале указана директива

 error_reporting (E_ALL);

Уведомление Trying to access array offset on value of type null/bool/int

Часто возникает при использовании синтаксиса обращения к элементу массива на других типах данных. Пример:

$a = false;
var_dump($a['somekey']);
// PHP 7.3: 
// NULL
// 
// PHP 7.4:
// Notice: Trying to access array offset on value of type bool in Command line code on line ...

Так бывает, например, если функция может возвращать массив в нормальном случае и false/null в случае ошибки, а дальше вверх по стеку информация о false/null теряется и этот случай не обрабатывается отдельно.

Решение - проверять с помощью is_array, является ли объект массивом.

Применение функции mysql_real_escape_string

...которой традиционно "обезопасивали" хранимые в базе данных строки от SQL-инъекций.

было: mysql_real_escape_string($s)

надо: mysqli_real_escape_string ($id,$s), где $id - идентификатор соединения MySQLi. Или хотя бы addslashes($s) - если нужно только экранировать "опасные" для SQL-запроса кавычки.

Перебор массива с помощью list и each

было: while (list(,$var) = each($params)) {

надо: foreach ($params as $var) {

или же: while (list($num,$var) = each($params)) {

а теперь: foreach ($params as $num=>$var) {

- если массив перебирается как ассоциативный и/или нужны ключи его элементов.

Модификатор /e функции preg_replace

было:
$text = preg_replace('~([0-9]+)\^([0-9]+)~e', 'pow("\\1", "\\2")', $text); //вычислить a^b

надо:
$text = preg_replace_callback('~([0-9]+)\^([0-9]+)~',
function ($m) { return pow($m[1], $m[2]); }, $text); //вычислить a^b

- то есть, через callback-функцию.

Проблема с подключаемыми графическими шрифтами GD

было:
$bbox=imagettfbbox ($f,0,'arial.ttf','String');

надо:
$font = dirname(__FILE__) . '/arial.ttf';
$bbox=imagettfbbox ($f,0,$font,'String');

- если фонт лежит в папке скрипта, как обычно и бывает.

То же самое с imageTtfText, например:

$font = dirname(__FILE__) . '/Roboto-Bold.ttf';
imageTtfText($myimg, $size, $angle, $j, 30, $c, $font, $z);

error_reporting(0) и подобное

Многие разработчики привыкли решать проблему с предупреждениями и даже сообщениями об ошибках просто выключая сообщения о них. При миграции скриптов это приводит к "загадочным белым экранам" вместо содержимого. Лучше всего вообще не трогать включённое в новых версиях протоколирование ошибок по умолчанию, а все вызовы функции error_reporting приводить к виду, указанному в начале статьи.

Строковые функции

Начиная с версии PHP 5.6 кодировкой по умолчанию стала кодировка Юникода UTF-8, соответственно, вместо прежних "си-подобных" строковых функций теперь лучше использовать их многобайтовые аналоги.

Наиболее часто приходится менять:

  • вместо strlen($s) писать mb_strlen($s,'UTF-8');
  • вместо strpos ($haystack,$needle,0) писать mb_strpos ($haystack,$needle,0,'UTF-8');
  • вместо strstr ($haystack,$needle,false) писать mb_strstr ($haystack,$needle,false,'UTF-8');
  • вместо substr ($string,$start,$length) писать mb_substr ($string,$start,$length,'UTF-8')

...и т.д., принцип, думаю, понятен. Будьте внимательны, проверяя, есть ли для функции многобайтовый аналог.

Для "бинарно безопасных" функций strcmp / strcasecmp, к примеру, таковых нет, а сравнение всё равно не работает:

<?php
 $s1="Привет";
 $s2="привет";
 echo strcasecmp($s1,$s2); //-32
?>

и нужно делать так:

<?php
 function mb_strcasecmp($str1, $str2, $encoding = null) {
  if (null === $encoding) { $encoding = mb_internal_encoding(); }
  return strcmp(mb_strtoupper($str1, $encoding), mb_strtoupper($str2, $encoding));
 }

 $s1="Привет";
 $s2="привет";
 echo mb_strcasecmp($s1,$s2,'UTF-8'); //0
?>

С другой стороны, как видно из примера, для strtoupper и strtolower эти аналоги есть.

Применение array_key_exists к объекту, а не к массиву

Теперь нельзя применять array_key_exists к объектам классов (а можно только к массивам). Неправильно:

 class foo {
  public $a, $b;
 };
 $bar = new foo();
 echo (array_key_exists('a',$bar) ? 'yes' : 'no'); //deprecated

Правильно:

  echo (property_exists($bar,'a') ? 'yes' : 'no'); //yes

Итак, 8-я версия, вышедшая в ноябре-2020, теперь есть и в составе XAMPP, ниже, вероятнее всего, будут добавляться исправления для PHP8, хотя и для версии 7 всё написанное выше остаётся в силе.

Отмечу, что в сборке PHP 8.0.0 с сайта XAMPP в файле php.ini ( диск:\xampp\php\php.ini ) была по умолчанию отключена библиотека gd:

;extension=gd

Соответственно, все функции imagecreatetruecolor, imagecreatefromgif, imagecreatefromjpeg, imagecreatefrompng и т.д. "вдруг перестали работать".

Решение - убрать точку с запятой из первой позиции указанной выше строки, сохранить изменённый php.ini, перезагрузиться.

Функция get_magic_quotes_gpc удалена (PHP8)

Любые упоминания о функции get_magic_quotes_gpc теперь придётся исключить из кода, она просто удалена. При этом нужно учесть, что начиная с версии 5.4 она всё равно всегда возвращала 0.

Почему нельзя было оставить в реализации пустое имя функции, а надо заставлять людей переделывать кучу кода - совершенно неясно.

И так у них всё :(

Функция each удалена (PHP8)

Удалена в PHP8 и функция each. В общем случае можно попытаться заменить на next или array_shift, но однозначного рецепта нет из-за возможности использования функции не только в цикле, как показано выше, но и, например, в рекурсивных построениях.

Фигурные скобки и литералы без кавычек для индексов массива (PHP8)

В PHP8 больше нельзя писать $a{$i} вместо $a[$i] или $foo[bar] вместо $foo['bar']. Просто исправьте это.

Разумеется, если ключ является числовой константой или берётся из переменной, заключать его в апострофы не нужно, $i = 1; $a[$i] или $a[1] - это верный синтаксис.

13.02.2020, 17:35 [22166 просмотров]


теги: ошибка список php

показать комментарии (1)