Назад в будущее или как переносился проект на PHP 4

Казалось бы все давно перешли с уже почившего в прошлом PHP 4 на PHP 5, ан нет, не все.
Недавно пришлось переделывать проект написанный изначально под PHP 5.2+ чтобы он был совместим с web серверами где всё ещё стоит PHP 4. По ходу переделок нашел много приятностей PHP 5.2+, о которых думал как о должном, забыл что в "древние времена" было иначе:

1. Непосредственное использование объекта, полученного в результате вызова функции:

$template = $settings->getByName('default_template')->value;

2. Использование ссылки на элемент массива при переборе массива с помощью комманды foreach:

foreach($items as &$item) { ... обработка ...}

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

3. Нет функций str_ireplace(), htmlspecialchars_decode(). С первой я расстался легко, т. к. регистронезависимость была не особо критична, а вот для htmlspecialchars_decode пришлось найти подмену:

  1. if (!]]>function_exists]]>("htmlspecialchars_decode")) {
  2. function htmlspecialchars_decode($string,$style=ENT_COMPAT)
  3. {
  4. $translation = ]]>array_flip]]>(]]>get_html_translation_table]]>(HTML_SPECIALCHARS,$style));
  5. if($style === ENT_QUOTES){ $translation['''] = '\''; }
  6. return ]]>strtr]]>($string, $translation);
  7. }
  8. }

4. В замечательной функции pathinfo в PHP 4 ещё не было константы PATHINFO_FILENAME, то есть получить имя файла без расширения с её помощью было нельзя. Заменить недостающий режим работы пришлось отдельной функцией:

  1. function get_file_name($path) {
  2. $base = ]]>pathinfo]]>($path, PATHINFO_BASENAME);
  3. $ext = ]]>pathinfo]]>($path, PATHINFO_EXTENSION);
  4. if (!$ext) return $base;
  5. $pos = ]]>strpos]]>($base, '.' . $ext);
  6. if (false === $pos) return $base;
  7. return ]]>substr]]>($base, 0, $pos);
  8. }

Это всё конечно мелочи, но все постепенные усовершенствования языка можно считать мелочью, к которой, тем не менее, быстро привыкаешь, если пользуешься.

5. Самым неприятным было отсутствие функции json_encode(). Эта проблема решается либо установкой PECL php_json, либо программными средствами. Вариант с установкой расширения не подходил, т.к. было несколько серверов куда нужно было установить разрабатываемую систему и для каждого перенастраивать PHP выходило неудобно. Основа была взята из примера с сайта http://kurapov.name/article/857/?&page=1 и немного исправлена:

  1. // json_encode function recovering
  2. if (!]]>function_exists]]>('json_encode')) {
  3. function json_encode($arr) {
  4. $parts = ]]>array]]>();
  5. $is_list = false;
  6. if (!]]>is_array]]>($arr)) return;
  7. if (]]>count]]>($arr)<1) return '{}';
  8. //Find out if the given array is a numerical array
  9. $keys = ]]>array_keys]]>($arr);
  10. $max_length = ]]>count]]>($arr)-1;
  11. if(($keys[0] == 0) and ($keys[$max_length] == $max_length)) {//See if the first key is 0 and last key is length - 1
  12. $is_list = true;
  13. for($i=0; $i<count($keys); $i++) { //See if each key correspondes to its position
  14. if($i !== $keys[$i]) { //A key fails at position check.
  15. $is_list = false; //It is an associative array.
  16. break;
  17. }
  18. }
  19. }
  20.  
  21. foreach($arr as $key=>$value) {
  22. if(]]>is_array]]>($value)) { //Custom handling for arrays
  23. if($is_list) $parts[] = json_encode($value); /* :RECURSION: */
  24. else $parts[] = '"' . $key . '":' . json_encode($value); /* :RECURSION: */
  25. } else {
  26. $str = '';
  27. if(!$is_list) $str = '"' . $key . '":';
  28. //Custom handling for multiple data types
  29. if(]]>is_numeric]]>($value)) $str .= $value; //Numbers
  30. elseif($value === false) $str .= 'false'; //The booleans
  31. elseif($value === true) $str .= 'true';
  32. else $str .= '"' . ]]>addslashes]]>($value) . '"'; //All other things
  33. // :TODO: Is there any more datatype we should be in the lookout for? (Object?)
  34. $str = ]]>str_replace]]>(]]>array]]>("\n", "\r", "\t"), ]]>array]]>('\n', '\r', '\t'), $str);
  35. $parts[] = $str;
  36. }
  37. }
  38. $json = ]]>implode]]>(',',$parts);
  39.  
  40. if($is_list) return '[' . $json . ']';//Return numerical JSON
  41. return '{' . $json . '}';//Return associative JSON
  42. }
  43. }

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

$str = ]]>str_replace]]>(]]>array]]>("\n", "\r", "\t"), ]]>array]]>('\n', '\r', '\t'), $str);

PS: если наблюдаются проблемы с кириллицей - можно предварительно обрабатывать передаваемый в json_encode объект следующей функцией:

  1. function json_fix_cyr($var)
  2. {
  3. if (]]>is_array]]>($var)) {
  4. $new = ]]>array]]>();
  5. foreach ($var as $k => $v) {
  6. $new[json_fix_cyr($k)] = json_fix_cyr($v);
  7. }
  8. $var = $new;
  9. } elseif (]]>is_object]]>($var)) {
  10. $vars = ]]>get_class_vars]]>(]]>get_class]]>($var));
  11. foreach ($vars as $m => $v) {
  12. $var->$m = json_fix_cyr($v);
  13. }
  14. } elseif (]]>is_string]]>($var)) {
  15. $var = ]]>iconv]]>(DEFAULT_CHARSET, 'utf-8', $var);
  16. }
  17. return $var;
  18. }

Комментарии

Отправить комментарий

  • Доступны HTML теги: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Строки и параграфы переносятся автоматически.
  • Search Engines will index and follow ONLY links to allowed domains.

Подробнее о форматировании

Введите решение задачи