Форумы портала PHP.SU » Разное » Обсуждение статей » Новые возможности в PHP 5.5

Страниц (1): [1]
 

1. EuGen - 21 Июня, 2013 - 11:20:06 - перейти к сообщению
Приветствую,
Вчера, 20 июня, вышел релиз php 5.5
Эта версия, как и 5.4 в своё время, добавила некоторые важные возможности, некоторые из которых я опишу здесь. Конечно, всё это есть в руководстве в том или ином виде, да и на том же habrahabr при желании можно найти статьи. Но всё же опишу то, что актуально в новой версии.

Итак, в PHP 5.5:
Появилась возможность разыменовывать строковые литералы и массивы напрямую
PHP:
скопировать код в буфер обмена
  1. echo 'Text data'[5];//5
  2. echo ['foo'=>'bar', 'baz'=>'fee']['baz'];//fee

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

Определение имени класса через ::class
- позволяет определять полный путь с учётом пространств имён, через слово class.
PHP:
скопировать код в буфер обмена
  1. namespace Bar;
  2. class Foo
  3. {
  4.    function __construct()
  5.    {
  6.       echo self::class;
  7.    }
  8. }
  9. new Foo; //Bar\Foo

- в принципе, ничего полезного этим не добавлено ввиду наличия константы __CLASS__

Добавлен блок finally
Этот синтаксис позволяет определить блок кода, который будет исполнен независимо от того, возникало ли исключение. Полезно, если, например, нужно в конечном итоге всегда закрыть соединение/файл:
PHP:
скопировать код в буфер обмена
  1. function putData($sFile, $sData)
  2. {
  3.    $bResult = true;
  4.    try
  5.    {
  6.       if(!$rFile = fopen($sFile, 'w'))
  7.       {
  8.          throw new IOException('Failed to open '.$sFile);
  9.       }
  10.       if(!fwrite($rFile, $sData))
  11.       {
  12.          throw new StreamException('Failed to write data');
  13.       }
  14.    }
  15.    catch(IOException $rException)
  16.    {
  17.       logError('Failed to fopen'.PHP_EOL);
  18.       $bResult = false;
  19.    }
  20.    catch(StreamException $rException)
  21.    {
  22.       logError('Failed to fwrite'.PHP_EOL);
  23.       $bResult = false;
  24.    }
  25.    finally
  26.    {
  27.       //no matter what it was above, we'll close stream, if it's present:
  28.       if($rFile)
  29.       {
  30.          fclose($rFile);
  31.       };
  32.       return $bResult;
  33.    }
  34. }

Спойлер (Отобразить)


Yield (генераторы)
Это не совсем очевидная вещь - но на деле очень простая. Генератор - это функция-итератор, которая по сути повторяет интерфейс Iterator. Вместо того, чтобы возвращать значение, такая функция генерирует его для текущего итератора. В мануале есть хороший пример для функции range. Преимущество генератора в том, что в памяти хранится лишь текущее значение, но не весь массив. Я модифицировал пример из мануала, чтобы показать, что происходит внутри генератора:
PHP:
скопировать код в буфер обмена
  1. function xrange($mStart, $mEnd, $mStep=1)
  2. {
  3.    if($mStart<$mEnd)
  4.    {
  5.       if($mStep<=0)
  6.       {
  7.          throw new Exception('Invalid step value');
  8.       }
  9.       for($i=$mStart; $i<=$mEnd; $i+=$mStep)
  10.       {
  11.          var_dump($i);
  12.          yield $i;
  13.       }
  14.    }
  15.    else
  16.    {
  17.       if($mStep>=0)
  18.       {
  19.          throw new Exception('Invalid step value');
  20.       }
  21.       for($i=$mStart; $i>=$mEnd; $i+=$mStep)
  22.       {
  23.          var_dump($i);
  24.          yield $i;
  25.       }  
  26.    }
  27. }
  28. foreach(xrange(1, 10, 3) as $mNumber)
  29. {
  30.    echo($mNumber.PHP_EOL);
  31. }

- то есть я просто добавил вывод переменной перед её "генерацией". Ключевое слово yield здесь заменяет return и сообщает, что мы хотим генерировать значение как функция-итератор, но не возвращать его. Результат будет таким:
CODE (htmlphp):
скопировать код в буфер обмена
  1. int(1)
  2. 1
  3. int(4)
  4. 4
  5. int(7)
  6. 7
  7. int(10)
  8. 10

- как видно, функция-генератор не исполняет цикл внутри себя, а использует его для генерации следующего значения. Откуда же берётся "следующее"? (То есть как функция понимает, какое текущее и, соответственно как генерировать это самое следующее)? Ответ очевиден - из блока, в котором содержится yield. Именно там мы указали, что именно мы желаем "yield" (сгенерировать). А сгенерировать мы желаем $i - именно это и будет счётчиком. А управляет им foreach, указанный при использовании генератора.

Это пока всё, с чем я успел поэкспериментировать, если возникнут вопросы или дополнения (в том числе и по тем нововведениям, что я не затронул) - предлагаю обсудить в этой теме.
2. DlTA - 21 Июня, 2013 - 12:15:29 - перейти к сообщению
интересно а будет ли когда нить добавлен для итераторов индексный доступ, как к массиву

$item = new newIteraor();
$item[10];
$item[5];
$item[20];
а то foreach это хорошо но как то мало
3. EuGen - 21 Июня, 2013 - 12:29:36 - перейти к сообщению
DlTA пишет:
интересно а будет ли когда нить добавлен для итераторов индексный доступ, как к массиву

Вопрос интересный, но неоднозначный. Дело тут в том, что легко спутать понятие "индекс массива" и "индекс итератора". Первое - есть по сути просто именованный указатель, тогда как второе - это порядковый номер последовательности, и, значит, должен быть натуральным числом (возможно, нулём). Поэтому обращение к итератору через индекс не до конца корректно - ведь индексом можно указать и строку, содержащую что угодно. Вероятно, это можно отслеживать, но на первый взгляд это создаёт больше проблем, чем решает. К тому же для вычисления N-го члена последовательности нужно выполнить генератор N раз (ведь он не хранит данные, а генерирует их), что, в случае сложного устройства последнего, может привести к медленной работе.
4. DelphinPRO - 21 Июня, 2013 - 12:57:49 - перейти к сообщению
EuGen пишет:
Определение имени класса через ::class
- позволяет определять полный путь с учётом пространств имён, через слово class.
...
- в принципе, ничего полезного этим не добавлено ввиду наличия константы __CLASS__


Константа __CLASS__ содержит в себе имя класса в котором она прописана. А если нам нужно получить имя унаследованного класса приходится использовать функцию get_class();
а как ведет себя ::class в этом случае?
пример

PHP:
скопировать код в буфер обмена
  1. class foo {
  2.   function myclass1(){
  3.      return __CLASS__;
  4.   }
  5.   function myclass2(){
  6.      return get_class($this);
  7.   }
  8.   function myclass3(){
  9.     return self::class;
  10.   }
  11. }
  12. class bar extends foo {
  13.  
  14. }
  15. $bar = new bar();
  16. echo $bar->myclass1(); // foo - не совсем то :)
  17. echo $bar->myclass2(); // bar - то, что надо!
  18. echo $bar->myclass3(); // ??? - а здесь что будет в php5.5?
5. EuGen - 21 Июня, 2013 - 13:02:13 - перейти к сообщению
DelphinPRO
Конечно же, это будет foo (к сожалению или нет - другой вопрос) - это очевидно из описания ::class
6. DelphinPRO - 21 Июня, 2013 - 13:04:18 - перейти к сообщению
я еще не читал мануал Улыбка
тогда, действительно, сомнительная полезность.. еще и на 4 символа больше писать )
7. EuGen - 25 Июня, 2013 - 12:30:40 - перейти к сообщению
Вместе с новыми возможностями, похоже, стала невозможной установка PECL-пакетов из репозитория. Если кто-то может проверить, буду признателен.
Спойлер (Отобразить)
8. caballero - 25 Июня, 2013 - 12:55:28 - перейти к сообщению
finally как я понял добавили
в других языках вещь необходимая но в PHP где контекст страницы все равно разрушается по окончании обработки оной - полезность тоже сомнительная
9. Мелкий - 25 Июня, 2013 - 15:24:04 - перейти к сообщению
EuGen, у меня собрался нормально.
CODE (bash):
скопировать код в буфер обмена
  1. root@debiansid:~# php -r 'var_dump(function_exists("ssh2_connect"), PHP_VERSION);'
  2. bool(true)
  3. string(7) "5.5.0-4"
  4.  

Но я взял php5.5 из debian sid.

Попробуйте
CODE (bash):
скопировать код в буфер обмена
  1. pecl download channel://pecl.php.net/ssh2-0.12

И посмотрите, что загрузилось. Похоже, что-то не то там.
10. EuGen - 25 Июня, 2013 - 15:42:17 - перейти к сообщению
Мелкий
Собрать - не проблема. Через phpize и ручную сборку всё в порядке (то есть скачать напрямую и потом собрать). Почему стандартный способ сборки отказывает - вот в чём вопрос. Вы пробовали собрать командой по-умолчанию? Скачалось, распаковалось, установилось?
11. Мелкий - 25 Июня, 2013 - 15:46:11 - перейти к сообщению
Не уточнил, да - это стандартным pecl'ом и ставил:
Спойлер (Отобразить)

ну и далее по тексту без моего вмешательства до победного "допишите extension=ssh2.so в конфиг".
(Добавление)
Заодно, версия pecl'а:
CODE (bash):
скопировать код в буфер обмена
  1. root@debiansid:~# pecl version
  2. PEAR Version: 1.9.4
  3. PHP Version: 5.5.0-4
  4. Zend Engine Version: 2.5.0-dev
  5. Running on: Linux debiansid 3.2.0-4-686-pae #1 SMP Debian 3.2.46-1 i686
12. EuGen - 25 Июня, 2013 - 17:22:15 - перейти к сообщению
Мелкий
Не очень понял, каким образом должно помочь pecl download (это именно работающая часть). Собственно, скачать удаётся, однако же установка не происходит. На bugs.php.net существует скудная информация - по поводу такой проблемы в альфа-версии 5.5
В любом случае - благодарю за тест, так стало ясно, что проблема не на pecl-репозитории в целом.
13. Мелкий - 25 Июня, 2013 - 17:35:42 - перейти к сообщению
EuGen пишет:
Не очень понял, каким образом должно помочь pecl download (это именно работающая часть).

Посмотреть, что именно скачалось, распаковывается ли, что в xml'ке.
Проблема-то на уровне распаковки и валидации описания пакета.

 

Powered by ExBB FM 1.0 RC1