Что лучше / быстрее / эффективнее в 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 довольно ограничены.
РЕДАКТИРОВАТЬ: Кажется, я недостаточно выразил это, но я специально спрашиваю о таком сценарии — когда создание объекта возвращает статическое значение, которое снова и снова используется внутри следующего цикла.
Чтобы взглянуть на это также под другим углом, давайте взглянем на оба сценария и код операции:
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
возражать только один раз и присваивать его переменной.
Также немного дополнительной информации:
Я пойду со следующим
$dateStep = new DateInterval('P1D');
for($di = 0; $di > $dateInterval; ++$di)
{
$theDate = ($di > 0) $startDate->add($dateStep);
...
}
Не рекомендуется создавать объект снова и снова внутри цикла, если в этом нет особой необходимости. В приведенном выше случае и объект создается перед циклом, и объекту передается экономия времени (для создания другого объекта) и пространства (без создания другого объекта в памяти).
Обе версии логически разные.
Первая версия передает одну и ту же ссылку на объект несколько раз. Это означает, что если вы измените $dateStep
после цикла вы меняете все что ссылки.
Вторая версия применяет ссылку на отдельный объект каждый раз, когда вы вызываете метод.
В примере с использованием DateTime::add()
метод, $dateStep
можно рассматривать как постоянное значение, которое не изменится. В этом случае первая версия является более быстрой и предпочтительной, поскольку ей не нужно каждый раз вызывать функцию конструктора, и ей требуется меньше памяти, поскольку объект просто необходимо создать один раз.
Определенно первый быстрее.
N экземпляров класса дороже, чем 1 объявление переменной.