Vladimir Kolesnikov Меня зовут Владимир, я программист-фрилансер (PHP, Node.js, C/C++, Qt). Ещё занимаюсь администрированием серверов и техническим переводом. Крестиком вышивать не умею.
Окт 072009
 

Как же всё запущено

В прошлой части:

  • if быстрее, чем switch;
  • echo быстрее, чем print;
  • явная проверка на (не)нулевое значение медленнее, чем неявная.

А также:

  • константные выражения, которые могут быть вычислены на этапе компиляции, не вычисляются;
  • не умеет удалять неиспользуемый код на этапе компиляции.

Продолжим.

Конкатенация или переменные внутри строки?

  Конкатенация Переменные внутри строки
Код
[-]
View Code PHP
<?php
    $tpl  = "str2";
    $text = 'str1 ' . $tpl . " str3\n";
    echo $text;
?>
[-]
View Code PHP
<?php
    $tpl  = "str2";
    $text = "str1 {$tpl} str3\n";
    echo $text;
?>
Результат
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   $tpl, 'str2'
   3     1  CONCAT                                           ~1      'str1 ', $tpl
         2  CONCAT                                           ~2      ~1, ' str3\n'
         3  ASSIGN                                                   $text, ~2
   4     4  ECHO                                                     $text
   6     5  RETURN                                                   1
         6* ZEND_HANDLE_EXCEPTION
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   $tpl, 'str2'
   3     1  INIT_STRING                                      ~1
         2  ADD_STRING                                       ~1      ~1, 'str1 '
         3  ADD_VAR                                          ~1      ~1, $tpl
         4  ADD_STRING                                       ~1      ~1, ' str3\n'
         5  ASSIGN                                                   $text, ~1
   4     6  ECHO                                                     $text
   6     7  RETURN                                                   1
         8* ZEND_HANDLE_EXCEPTION

Вывод: конкатенация быстрее, и, как показал тест (путём замены echo $text; на echo memory_get_usage();), потребляет меньше памяти.

Цикл со счётчиком: while или for?

  for while
Код
[-]
View Code PHP
<?php
    for ($i=0; $i<1000; ++$i) {
    }
?>
[-]
View Code PHP
<?php
    $i = 0;
    while ($i<1000) {
        ++$i;
    }
?>
Результат
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   $i, 0
         1  IS_SMALLER                                       ~1      $i, 1000
         2  JMPZNZ                                        5          ~1, ->6
         3  PRE_INC                                                  $i
         4  JMP                                                      ->1
   3     5  JMP                                                      ->3
   7     6  RETURN                                                   1
         7* ZEND_HANDLE_EXCEPTION
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   $i, 0
   3     1  IS_SMALLER                                       ~1      $i, 1000
         2  JMPZ                                                     ~1, ->5
   4     3  PRE_INC                                                  !0
   5     4  JMP                                                      ->1
   9     5  RETURN                                                   1
         6* ZEND_HANDLE_EXCEPTION

Вывод: хотя цикл while выглядит многословнее (по крайней мере, длиннее), он, на удивление, оказывается короче полностью аналогичного цикла for. Таким образом, не всегда более короткий код оказывается более эффективным. При этом так как второй вариант короче (в плане количества опкодов), он потребляет меньше памяти.

Пустая строка или NULL?

  Пустая строка null
Код
[-]
View Code PHP
<?php
    $a = "";
    echo memory_get_usage();
?>
[-]
View Code PHP
<?php
    $a = NULL;
    echo memory_get_usage();
?>
Результат 106,336 106,224

Вывод: использование пустых значений «сложных» типов (строки, массивы, объекты) ведёт к повышенному потреблению памяти. Использование NULL — самый оптимальный вариант.

is_null() или строгая проверка на NULL?

  is_null Строгое соответствие
Код
[-]
View Code PHP
<?php
    $a = 0;
    if (is_null($a)) {
    }
?>
[-]
View Code PHP
<?php
    $a = 0;
    if ($a === NULL) {
    }
?>
Результат
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   $a, 0
   3     1  SEND_VAR                                                 $a
         2  DO_FCALL                                      1          'is_null'
         3  JMPZ                                                     $1, ->5
   4     4  JMP                                                      ->5
   6     5  RETURN                                                   1
         6* ZEND_HANDLE_EXCEPTION
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ASSIGN                                                   $a, 0
   3     1  IS_IDENTICAL                                     ~1      $a, null
         2  JMPZ                                                     ~1, ->4
   4     3  JMP                                                      ->4
   6     4  RETURN                                                   1
         5* ZEND_HANDLE_EXCEPTION

Вывод: проверка на строгое равенство NULL работает быстрее, в том числе из-за отсутствия необходимости вызова функции.

echo: конкатенация или запятые?

  Конкатенация Запятые
Код
[-]
View Code PHP
<?php
    echo 'Memory ' . 'usage ' . 'is ' . memory_get_usage() . "\n";
?>
[-]
View Code PHP
<?php
    echo 'Memory ', 'usage ', 'is ', memory_get_usage(), "\n";
?>
Результат
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  CONCAT                                           ~0      'Memory ', 'usage '
         1  CONCAT                                           ~1      ~0, 'is '          
         2  DO_FCALL                                      0          'memory_get_usage'
         3  CONCAT                                           ~3      ~1, $2            
         4  CONCAT                                           ~4      ~3, '\n'          
         5  ECHO                                                     ~4
   3     6  RETURN                                                   1
         7* ZEND_HANDLE_EXCEPTION
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  ECHO                                                     'Memory '
         1  ECHO                                                     'usage '
         2  ECHO                                                     'is '
         3  DO_FCALL                                      0          'memory_get_usage'
         4  ECHO                                                     $0
         5  ECHO                                                     '\n'
   3     6  RETURN                                                   1
         7* ZEND_HANDLE_EXCEPTION
  Memory usage is 106192 Memory usage is 106184

Выводы: в очередной раз менее читабельный метод оказался лучшим — на этот раз в плане потребления памяти. И, как видим, PHP не догадался даже объединить строки вместе.

Что быстрее: статический или динамический метод?

  Динамический метод Статический метод
Код
[-]
View Code PHP
<?php
    class A {
        public function test() {}
    }

    $a = new A;
    $a->test();
?>
[-]
View Code PHP
<?php
    class A {
        public static function test() {}
    }

    $a = new A;
    A::test();
?>
Результат
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  NOP                                                                
   6     1  ZEND_FETCH_CLASS                                 :1      'A'      
         2  NEW                                              $2      :1        
         3  DO_FCALL_BY_NAME                              0                    
         4  ASSIGN                                                   $a, $2    
   7     5  ZEND_INIT_METHOD_CALL                            $5      $a, 'test'
         6  DO_FCALL_BY_NAME                              0                    
   8     7  RETURN                                                   1        
         8* ZEND_HANDLE_EXCEPTION
[-]
View Code Text
line     #  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
   2     0  NOP                                                                
   6     1  ZEND_FETCH_CLASS                                 :1      'A'      
         2  NEW                                              $2      :1        
         3  DO_FCALL_BY_NAME                              0                    
         4  ASSIGN                                                   $a, $2    
   7     5  ZEND_FETCH_CLASS                                 :5      'A'      
         6  ZEND_INIT_STATIC_METHOD_CALL                             null, 'test'
         7  DO_FCALL_BY_NAME                              0                      
   8     8  RETURN                                                   1          
         9* ZEND_HANDLE_EXCEPTION

Выводы: при прочих равных условиях, вызов статического метода на один опкод длиннее вызова динамического метода. Таким образом, если делать все методы класса, которые не используют $this, статическими, это приведёт к потреблению памяти.

Спички спичками, но сколько таких спичек экономится в мало-мальски сложном скрипте (таком, как WordPress). Пусть результат от одной сэкономленной спички ничтожно мал, но помноженный на количество таких потенциальных спичек во всём коде, становится весьма и весьма ощутимым, особенно на слабом железе.

  7 Ответов в “PHP: красота кода сказывается на производительности: часть 2”

Comments (6) Pingbacks (1)
  1. Completely agree, your article is amazing, thanks for sharing with us!!!this was really useful

  2. А я все равно считаю, что больший приоритет надо отдавать читабельности кода, но в пределах разумного (всячески избегать рекурсии например). А оптимизацией пусть занимаются разработчики компиляторов

  3. А зачем вы перед вызовом статического метода объект создавали?

Leave a comment below if you dare

If by accident you see this form, please do not use it; use the form below this instead.

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

(обязательно)

(обязательно)

Вы можете использовать эти HTML теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, вы выражаете своё согласие с Правилами комментирования.