Переход на PHP7: работа над ошибками
Итак, у вас есть старенький, но уж очень милый сердцу сайт, который вы решаетесь из жалости (или, возможно, перечитав Хабра) перевести на PHP7. С волнением ожидая резкого роста производительности, вы смахиваете пыль с бедного сайта и решительно переключаете в панели управления хостингом версию PHP.
Если сайт уже давно не молод, то с большой долей вероятности чудо не произойдет. В лучшем случае начнут появляться разного рода ошибки, а в худшем — вы увидите белый экран, дзен веб-разработки. В этот момент хочется по-быстрому переключить все обратно и забыть о своей внезапной слабости.
Но предположим, что ваша сильная сторона — настойчивость, к тому же вы располагаете некоторым количеством времени для экспериментов. Давайте попробуем все починить.
Резервные копии
Делаем резервные копии сайта (а заодно и баз данных). Ведь кто не делает резервные копи — сам себе враг, верно? Для разного рода экспериментов имеет смысл добавить еще один сайт на хостинге и скопировать в него файлы, которые мы сейчас будем править.
Журналы ошибок
Настроим ведение журнала ошибок PHP в файл .htaccess (если он не был настроен ранее):
php_value display_errors 0
php_value log_errors 1
php_value error_log /home/vasya/domains/mysite.ru/logs/error.log
Подробно о ведении журналов мы уже писали в нашем блоге ранее.
Работа с MySQL
Допустим, сайт использует базы данных, и вы видите ошибки вроде такой:
Fatal error: Uncaught Error: Call to undefined function mysql_connect()
Это оттого, что в современных версиях PHP (начиная с PHP 5.5.0) оригинальное расширение MySQL не поддерживается. Разработчики рекомендуют использовать MySQLi или PDO. Попробуем перейти на MySQLi, это просто:
Предположим, что сайт написан с использованием процедурного подхода, который представляет собой классический говнокод многие и сейчас считают лаконичным и эффективным решением. В таком случае, следующую устаревшую конструкцию для подключения к базе данных:
$link = mysql_connect(‘localhost’, $user, $password)
mysql_select_db($dbname, $link)
mysql_query(‘set names cp1251’)
можно заменить на:
$link = mysqli_connect(‘localhost’, $user, $password, $dbname)
mysqli_query($link, ‘set names cp1251’)
для запросов:
$result=mysql_query($query,$cid)
заменить на:
$result=mysqli_query($cid, $query)
Другие популярные функции легко меняются на их аналоги с буквой ‘i’:
mysqli_fetch_array()
mysqli_fetch_row()
mysqli_fetch_assoc()
mysqli_fetch_array()
mysqli_num_rows()
mysqli_insert_id()
mysqli_close()
В результате этих несложных действий данные из БД должны успешно собираться и отправляться.
Кодировка
Настоящий олдскул — это сайт в CP1251 (как минимум). Всё превратилось в ромбики или прочие козяблики?
Скорее всего, достаточно будет указать кодировку в .htaccess таким образом:
php_value default_charset «cp1251»
Регулярные выражения
Также вы можете наблюдать ошибки следующего рода:
Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
Это означает, что модификатор /e, который позволял передать произвольной функции результат регулярного выражения, теперь не поддерживается. В таких случаях рекомендуется использовать функцию preg_replace_callback
Допустим, у нас есть такое регулярное выражение:
$string=preg_replace(«/:([a-z]{1,10}):/e», «print_smile(‘\\1’)», $string)
с заменой на preg_replace_callback оно должно выглядеть вот так:
$string=preg_replace_callback(«/:([a-z]{1,10}):/», create_function(‘$matches’, ‘return print_smile($matches[1])’), $string)
здесь все просто, регулярное выражение теперь указывается в качестве первого аргумента (без модификатора /e, разумеется), а в качестве второго аргумента указывается анонимная функция (которая будет выполнена после применения регулярного выражения) с двумя аргументами: массив $matches, где будут сохранены данные, совпадающие с регулярным выражением и вызов внешней функции с аргументами. В данном примере внешняя функция называется print_smile и ей передается аргументом первое найденное вхождение. То, что в preg_replace было \\1 (первое найденное вхождение) станет $matches[1] (если аргументов было больше, то будет $matches[2], $matches[3] и так далее).
Вот еще один пример, посложнее:
Было так:
$out=preg_replace(«/<[Rr][Mm]( [Mm][Ss][Gg]=[\’\»]{0,1}|)(.*?)([\’\»]{0,1})>(.*?)<\/[Rr][Mm]>/es», «feed_out_sub_rm(‘\\2′,’$base_prefix’,’$nick’,’$id_entry’)», $out)
Стало вот так:
$out=preg_replace_callback(‘/<[Rr][Mm]( [Mm][Ss][Gg]=[\’\»]{0,1}|)(.*?)([\’\»]{0,1})>(.*?)<\/[Rr][Mm]>/s’, create_function(‘$matches’, ‘return feed_out_sub_rm($matches[2], «‘.$base_prefix.'», «‘.$nick.'», «‘.$id_entry.'») ‘), $out)
здесь легко запутаться в кавычках, будьте внимательны.
Копаясь в регулярных выражениях, можно вспомнить еще про две функции, которые с версии PHP 5.3.0 считаются устаревшими (и не поддерживаются). Симптомы следующие:
Fatal error: Uncaught Error: Call to undefined function ereg_replace()
Если регулярное выражение в ereg_replace простое, то можно обойтись просто установкой граничных символов, как здесь:
$str=ereg_replace(«[\r\t\n]»,»»,$str)
$str=preg_replace(«/[\r\t\n]/»,»»,$str)
Аналогичный симптом:
Fatal error: Uncaught Error: Call to undefined function split()
Было:
$var_pair=split(«=»,$tmp[3])
Стало:
$var_pair=explode(«=»,$tmp[3])
Если регулярное выражение посложнее, то пробуем преобразовать к preg_split.
На этом пока все. Удачной отладки.
Много полезных материалов по теме можно найти на сайте разработчиков.
Если что-то не получается, или ваш случай совсем не похож на наши примеры — пишите комментарии, попробуем разобраться вместе.
Для того, чтобы оставлять комментарии к посту, авторизуйтесь, используя свой аккаунт в социальных сетях ВКонтакте/FaceBook, или аккаунт в Google/Яндекс.
PHP 7 работает до двух раз быстрее чем PHP 5.6. Имхо оно того стоит, нужно переходить на php7.
когда слышал по телевизору про новый стиральный порошок, который отстирывает на 30% лучше чем старый, думал, что у домохозяек проблемы с мозгом, если они на эту фигню ведутся. теперь вижу, что не только у домохозяек 😉
>> PHP 7 работает до двух раз быстрее чем PHP 5.6