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

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

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

Уведомление 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');

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

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 эти аналоги есть.


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

13.02.2020, 17:35; рейтинг: 84