Создание дополнительной переменной или объекта — что лучше в PHP?

Что лучше / быстрее / эффективнее в PHP?

Используя дополнительную переменную:

$dateStep = new DateInterval('P1D');

for($di = 0; $di <= $dateInterval; ++$di)
{
$theDate = ($di > 0) ? $startDate->add($dateStep) : $startDate;

...
}

Или создавая объект каждый раз, когда это требуется:

for($di = 0; $di <= $dateInterval; ++$di)
{
$theDate = ($di > 0) ? $startDate->add(new DateInterval('P1D')) : $startDate;

...
}

Я бы проголосовал за первый вариант, но мои знания в области оптимизации и производительности в PHP довольно ограничены.

РЕДАКТИРОВАТЬ: Кажется, я недостаточно выразил это, но я специально спрашиваю о таком сценарии — когда создание объекта возвращает статическое значение, которое снова и снова используется внутри следующего цикла.

3

Решение

Чтобы взглянуть на это также под другим углом, давайте взглянем на оба сценария и код операции:

script1:

<?php

$dateStep = new DateInterval('P1D');
$dateInterval = 5;
$startDate = new DateTime();

for($di = 0; $di <= $dateInterval; ++$di)
{
$theDate = ($di > 0) ? $startDate->add($dateStep) : $startDate;

//...
}

опкод:

number of ops:  26
compiled vars:  !0 = $dateStep, !1 = $dateInterval, !2 = $startDate, !3 = $di, !4 = $theDate
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
3     0  >   FETCH_CLASS                                   4  :0      'DateInterval'
1      NEW                                              $1      :0
2      SEND_VAL                                                 'P1D'
3      DO_FCALL_BY_NAME                              1
4      ASSIGN                                                   !0, $1
4     5      ASSIGN                                                   !1, 5
5     6      FETCH_CLASS                                   4  :5      'DateTime'
7      NEW                                              $6      :5
8      DO_FCALL_BY_NAME                              0
9      ASSIGN                                                   !2, $6
7    10      ASSIGN                                                   !3, 0
11  >   IS_SMALLER_OR_EQUAL                              ~10     !3, !1
12    > JMPZNZ                                        F          ~10, ->25
13  >   PRE_INC                                                  !3
14    > JMP                                                      ->11
9    15  >   IS_SMALLER                                       ~12     0, !3
16    > JMPZ                                                     ~12, ->22
17  >   INIT_METHOD_CALL                                         !2, 'add'
18      SEND_VAR                                                 !0
19      DO_FCALL_BY_NAME                              1  $14
20      QM_ASSIGN_VAR                                    $15     $14
21    > JMP                                                      ->23
22  >   QM_ASSIGN_VAR                                    $15     !2
23  >   ASSIGN                                                   !4, $15
12    24    > JMP                                                      ->13
25  > > RETURN                                                   1

Скрипт2:

<?php$dateInterval = 5;
$startDate = new DateTime();

for($di = 0; $di <= $dateInterval; ++$di)
{
$theDate = ($di > 0) ? $startDate->add(new DateInterval('P1D')) : $startDate;

// ...
}

опкод:

number of ops:  25
compiled vars:  !0 = $dateInterval, !1 = $startDate, !2 = $di, !3 = $theDate
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
4     0  >   ASSIGN                                                   !0, 5
5     1      FETCH_CLASS                                   4  :1      'DateTime'
2      NEW                                              $2      :1
3      DO_FCALL_BY_NAME                              0
4      ASSIGN                                                   !1, $2
7     5      ASSIGN                                                   !2, 0
6  >   IS_SMALLER_OR_EQUAL                              ~6      !2, !0
7    > JMPZNZ                                        A          ~6, ->24
8  >   PRE_INC                                                  !2
9    > JMP                                                      ->6
9    10  >   IS_SMALLER                                       ~8      0, !2
11    > JMPZ                                                     ~8, ->21
12  >   INIT_METHOD_CALL                                         !1, 'add'
13      FETCH_CLASS                                   4  :10     'DateInterval'
14      NEW                                              $11     :10
15      SEND_VAL                                                 'P1D'
16      DO_FCALL_BY_NAME                              1
17      SEND_VAR_NO_REF                               0          $11
18      DO_FCALL_BY_NAME                              1  $13
19      QM_ASSIGN_VAR                                    $14     $13
20    > JMP                                                      ->22
21  >   QM_ASSIGN_VAR                                    $14     !1
22  >   ASSIGN                                                   !3, $14
12    23    > JMP                                                      ->8
24  > > RETURN                                                   1

Теперь, как вы можете видеть из кода операции второго скрипта, он создает новый экземпляр класса каждую итерацию, и вы создаете огромные накладные расходы, которые, похоже, вам не нужны (посмотрите на # * 13 - 16 во втором опкоде), поэтому сначала вы создаете новые экземпляры, которые совершенно не нужны, а во-вторых, это замедлит вашу производительность.

Так что, если вам не нужен совершенно новый класс на каждой итерации, первый скрипт лучше для вас, поскольку он только создает DateInterval возражать только один раз и присваивать его переменной.

Также немного дополнительной информации:

2

Другие решения

Я пойду со следующим

$dateStep = new DateInterval('P1D');

for($di = 0; $di > $dateInterval; ++$di)
{
$theDate = ($di > 0) $startDate->add($dateStep);

...
}

Не рекомендуется создавать объект снова и снова внутри цикла, если в этом нет особой необходимости. В приведенном выше случае и объект создается перед циклом, и объекту передается экономия времени (для создания другого объекта) и пространства (без создания другого объекта в памяти).

2

Обе версии логически разные.

Первая версия передает одну и ту же ссылку на объект несколько раз. Это означает, что если вы измените $dateStep после цикла вы меняете все что ссылки.

Вторая версия применяет ссылку на отдельный объект каждый раз, когда вы вызываете метод.


В примере с использованием DateTime::add() метод, $dateStep можно рассматривать как постоянное значение, которое не изменится. В этом случае первая версия является более быстрой и предпочтительной, поскольку ей не нужно каждый раз вызывать функцию конструктора, и ей требуется меньше памяти, поскольку объект просто необходимо создать один раз.

2

Определенно первый быстрее.
N экземпляров класса дороже, чем 1 объявление переменной.

1