×
FAQ: Технические вопросы

Переход на PHP5+MySQL5

Переход с РНР 4 на РНР 5

По сравнению с предыдущей версией PHP 5 содержит большое количество нововведений и доработок. Перечислим основные из них:

  • Изменение в модели объектно-ориентированного программирования в Zend Engine 2, что дает ощутимый прирост в скорости выполнения большинства скриптов;
  • Объектно-ориентированный интерфейс в дополнение к стандартному в новом расширении MySQLi;
  • Обновленная поддержка XML в библиотеке libxml версии 2;
  • Работа с XML как с PHP-объектами в новом расширении SimpleXML;
  • Улучшенные механизмы использования потоков.

Многие CMS поддерживают как PHP 4, так и PHP 5, причём в последних версиях некоторых программных продуктов (например, Drupal 7) присутствует только поддержка PHP 5.

Описание некоторых проблем, возникающих при переходе с PHP 4 на PHP 5:

Режим совместимости

В PHP 4 при передаче объектов в функцию эти объекты копируются; в PHP 5 передается оригинальный объект. В ряде случаев это может привести к ошибкам. Решением может служить передача в функцию клона объекта (clone($obj)) вместо самого объекта.

Более радикальным и надежным представляется изменение настроек PHP 5, а именно — включение режима совместимости (compatibility mode). Для этого следует включить директиву zend.ze1_compatibility_mode в конфигурационном файле php.ini или .htaccess, либо при помощи функции ini_set():

php_flag zend.ze1_compatibility_mode on
или
<?php
ini_set('zend.ze1_compatibility_mode'true);
?>

Помимо смены способа передачи объектов в функции, режим совместимости влияет также на кастинг объектов и их сравнение — при его использовании указанные операции производятся по стандарту PHP 4.

Кастинг объектов

В PHP 4 результат приведения объектов к логическому, целочисленному или типу чисел с плавающей запятой зависел от наличия у объекта переменных. Если объект обладал хотя бы одной переменной, результатом приведения была единица; в противном случае — ноль. В PHP 5 результат приведения всегда равен единице.

<?php
print (int) new stdClass// 1
?>
В PHP5 объект без свойств больше не считается «пустым»:
<?php
class test { }
$t = new test();

var_dump(empty($t)); // echo bool(false)

if ($t) {
   // Будет выполнено
}
?>

Сравнение объектов

В PHP 4 оператор равенства (==), примененный к двум объектам, возвращает true, если все переменные у обоих объектов равны. В PHP 5 для того, чтобы объекты считались равными, необходимо дополнительное уловие: они должны принадлежать одному и тому же классу.

Присвоение $this

Если до введения новой объектной модели можно было свобоно использовать переменную $this по своему усмотрению, то с пятой версии такая конструкция невозможна — нельзя переопределять зарезервированную переменную $this.

<?php
class Foo {
    function Foo($class)
    {
        $this = new $class;
    }
}

class Bar {
}

$foobar = new Foo('Bar');
        
// Fatal error:  Cannot re-assign $this
?>

Существует несколько решений этой проблемы — от эмуляции присвоения путем статического вызова конструктора «присваемого» класса до генерации исключительной ситуации или ее эмуляции. Однако наиболее предпочтительным и совместимым с обеими версиями PHP методом является использование шаблона-одиночки (singleton).

<?php

class SingletonClass
{
   private static $hash = array();

   public static function singleton($class)
   {
       if (!array_key_exists($classSingletonClass::$hash))
       {
           SingletonClass::$hash[$class] = new $class;
       }
       return SingletonClass::$hash[$class];
   }
}

class BarClass
{
   private $value;

   public function __construct()
   {
       $this->value 0;
   }

   public function setValue($value)
   {
       $this->value $value;
   }

   public function getValue()
   {
       return $this->value;U
   }
}

$bar1 SingletonClass::singleton('BarClass');
$bar1->setValue(6);

$bar2 SingletonClass::singleton('BarClass');

echo $bar2->getValue();

?>

Список новых зарезервированных слов

Помимо this, в PHP5 введены следующие зарезервированные слова, которые теперь нельзя использовать для именования функций и переменных:

  • final
  • php_user_filter
  • interface
  • implements
  • extends
  • public
  • private
  • protected
  • abstract
  • clone
  • try
  • catch
  • throw
  • exception
  • this

Функция get_class()

В PHP 5 эта функция возвращает название класса с сохранением регистра, в то время как PHP 4 всегда приводит название класса к нижнему регистру. Для совместимости можно использовать следующий код:

<?php
$cname strtolower(get_class($obj));
?>

Уровень сообщений E_STRICT

В PHP 5 вводится новый уровень сообщений — E_STRICT, который может быть включен путем установки директивы, управляющей уровнем сообщений об ошибках, в состояние E_ALL | E_STRICT.

<?php
error_reporting(E_ALL E_STRICT);
?>

Сообщения уровня E_STRICT генерируются в тех случаях, когда в коде используются устаревшие возможности предыдущих версий PHP. Несколько таких устаревших возможностей:

Автоматическое создание объектов

При попытке присвоить значение несуществующей переменной несуществующего объекта автоматически создается новый объект класса stdClass.

<?php
$foo->bar true;   // deprecated!
?>

Объявление переменных класса (var)

Поддерживается только ради обратной совместимости. Следует использовать модификаторы уровня доступа: public, protected или private.

Устаревший конструктор

Конструктор с именем, совпадающим с названием класса, поддерживается только ради обратной совместимости. Следует использовать унифицированный конструктор __construct.

Перекрытие наследуемых методов

Изменение объявления одноименных методов в наследуемых классах (изменение числа параметров) не приветствуется в PHP 5.

Функция xslt_create

После перехода на РНР 5 вы стали получать ошибку вида «PHP Fatal error: Call to undefined function xslt_create()»? В РНР 5 существенно поменялось API, вследствии чего функция xslt не поддерживается, поэтому разработчики рекомендуют вместо данной функции использовать xsl:

В этом случае есть два выхода:

  1. Переписать код ваших скриптов, используя XSL.
  2. Подключить дополнительный файл, который позволяет использовать функции xslt_create & etc в php5. Для этого нужно подключить файл xslt-php4-to-php5.php в скрипт в котором выполняется xslt_create, например, так:
    if (version_compare(PHP_VERSION,'5','>=')&&extension_loaded('xsl'))
    require_once('xslt-php4-to-php5.php');

Второй вариант лучше всего рассматривать как временый, т.к. адаптировав свой код к PHP 5, вы увеличите производительность работы ваших проектов.

Отметим, что подключение функций возможно только в том случае, если вы используете основой PHP, а не скомпилированный. В случае, если вы будете компилировать свой PHP с библиотекой libxslt, то возможно подключить только libxslt версии 1.1.17.

Функция xml_parser_create

В PHP выше 5.0.2 функция xml_parser_create работает в кодировке utf-8.

Здесь могут возникнуть сложности если вы используете информацию из баз данных в кодировке Windows-1251. Для ее разрешения необходимо преобразовать полученные из базы данные:

$data mb_convert_encoding($data"UTF-8""Windows-1251");
где $data — преобразуемые данные.

Внимание!

В обязательном порядке необходимо ознакомиться со списком нововведений, повлекших за собой обратную несовместимость с предыдущими версиями PHP. Ваши скрипты в ряде случаев могут перестать корректно работать при смене версии интерпретатора. Перед переходом на новую версию постарайтесь убедиться в том, что написанные вами скрипты полностью совместимы с новой версией. Даже если перенос прошел без видимых проблем, советуем вам первое время обращать внимание на любые ошибки, возникающие при выполнении ваших скриптов.

Переход с MySQL 4.x.x на MySQL 5.x.x

Теперь на нашем хостинге доступна новая версия MySQL — 5.0.24. Новая версия работает быстрее, а база данных занимает до 20% меньше места на диске. Обо всех нововведениях вы можете почитать в документации на официальном сайте.

В новой версии MySQL появилась новая служебная база данных — INFORMATION_SCHEMA. Она решает задачу реализации словаря данных (data dictionary). INFORMATION_SCHEMA содержит таблицы, описывающие состояние и параметры сервера, в том числе определения и сущности таблиц. Это виртуальная база данных — физически (в виде файлов на диске) она не существует, вся информация динамически предоставляется сервером. Пример использования этой таблицы:

SELECT table_name, table_type, engine
FROM INFORMATION_SCHEMA.tables
WHERE table_schema = ‘tp’
+------------+------------+--------+
| table_name | table_type | engine |
+------------+------------+--------+
| t1         | BASE TABLE | MyISAM |
| t2         | BASE TABLE | MyISAM |
| v1         | BASE TABLE | MyISAM |
+------------+------------+--------+

Обратите внимание!

MySQL 5 имеет некоторые несовместимости с предыдущими версиями, полный список несовместимостей вы найдете здесь.

Проблемы с кодировками

Основная проблема, с которой сталкиваются пользователи при переходе с версий до 4.1 — проблема с кодировками. Причина данной проблемы в том, что MySQL 5 хранит все данные в кодировке UTF-8. Установленный у нас MySQL настроен так, чтобы при операциях ввода/вывода автоматически конвертировать данные из UTF-8 в Windows-1251 и обратно. Однако в некоторых ситуациях (например, если вы передаете в базу данные в кодировке KOI8-R или UTF-8) данные могут загружаться ошибочно или не загружаться совсем (на запрос вместо символов будут выдаваться знаки вопроса).

Возможны два варианта:

  1. Клиент использует неправильную кодировку

    Симптомы следующие:

    • а) В phpMyAdmin (версии 2.6.0 или выше) содержимое таблиц отображается корректно, а в скрипт приходят вопросительные знаки.
    • б) Скрипт отправляет в базу данных заведомо русский текст, после чего на запросы к базе как в скрипт, так и в phpMyAdmin возвращаются знаки вопроса.

    Решение:

    • Попробуйте в начале скрипта, сразу после инициализации соединения с базой данных, выполнить SQL-команду:
      SET NAMES кодировка

    Где «кодировка» — та кодировка, в которой у вас (по вашему мнению) данные. Это может быть, например, cp1251, koi8r, utf8 и другие.

    Если буквы стали русскими — данные в базе находятся в правильной кодировке. Если буквы стали русскими, но слова не читаются (например, вместо слова «вопрос» возвращается слово «бнопня») — надо попробовать другую кодировку.

  2. MySQL использует неправильную кодировку

    Симптомы следующие:

    • Скрипт получает русский текст, но не работают функции сортировки, перевода в верхний/нижний регистр и т.п. Обычно это сопровождается неправильным отображением данных в phpMyAdmin.

    Диагностика:

    • Необходимо попробовать выполнить в phpMyAdmin следующий запрос:

      SELECT CONVERT(CONVERT(поле USING binary) USING кодировка) FROM таблица;
      Где «таблица», «поле» — соответственно таблица и ее поле, в котором хранится русский текст, «кодировка» — предполагаемая правильная кодировка. Если данные в результате запроса стали отображаться правильно — необходимо конвертировать таблицу.

    Решение:

    • Обязательно сделайте полный backup вашей базы данных, прежде чем выполнять конвертирование таблиц!

      Конвертирование полей происходит следующим образом:

      Например, есть таблица T со столбцом R, тип которого CHAR (50). Необходимо конвертировать содержимое данного столбца в кодировку cp1251. Выполняем следующие две команды:

      ALTER TABLE T MODIFY R BINARY (50);
      ALTER TABLE T MODIFY R CHAR (50) CHARACTER SET cp1251;

      Обратите внимание, что после BINARY в скобках указан размер поля. Если вы конвертируете поле типа TEXT, необходимо указать достаточно большое значение. В противном случае текст будет обрезан.

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

Особенности работы оператора JOIN

В предыдущих версиях MySQL оператор запятая (,) и JOIN имели одинаковый приоритет и выполнялись по порядку вхождения в запросе. Поэтому выражение

t1, t2 JOIN t3
интерпретировалось как
((t1, t2) JOIN t3)

В пятой версии оператор JOIN имеет более высокий приоритет, и описанное выше выражение интерпретируется иначе:

(t1, (t2 JOIN t3))

При этом может возникнуть ошибка:

Unknown column 't1.name' in 'on clause'

Для решения данной проблемы, необходимо изменить запрос, взяв в скобки имена таблиц после оператора FROM. Например, запрос:

SELECT count(*)FROM table1 t1, table2 t2 JOIN table3 t3 ON t1.id = t3.id WHERE …
надо заменить на:
SELECT count(*)FROM (table1 t1, table2 t2) JOIN table3 t3 ON t1.id = t3.id WHERE …