额外变量或对象创建——PHP 哪个更好?
Extra variable or object creation -- what is better in 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 的优化和性能方面的知识非常有限。
编辑:看来,我表达得还不够,但我特别要求这样的场景——当创建object returns 静态值,在以下循环中反复使用。
绝对是第一个更快。
N class 个实例比 1 个变量声明更昂贵。
我会选择以下
$dateStep = new DateInterval('P1D');
for($di = 0; $di > $dateInterval; ++$di)
{
$theDate = ($di > 0) $startDate->add($dateStep);
...
}
不建议在循环中一遍又一遍地创建一个对象,除非确实有必要。在上述情况下,对象是在循环之前创建的,并且传递对象可以节省时间(用于创建另一个对象)和 space(通过不在内存中创建另一个对象)。
两个版本在逻辑上是不同的。
第一个版本多次传递同一个对象引用。这意味着如果您在循环后更改 $dateStep
,您将更改引用的 all。
第二个版本在您每次调用该方法时应用对单个对象的引用。
在使用DateTime::add()
方法的例子中,$dateStep
可以看作是一个不变的常量值。在那种情况下,第一个版本更快,更可取,因为它不需要每次都调用构造函数,而且它确实需要更少的内存,因为对象只需要创建一次。
为了从另一个角度来看这个问题,让我们看看脚本和操作码:
脚本 1:
<?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 :0
2 SEND_VAL 'P1D'
3 DO_FCALL_BY_NAME 1
4 ASSIGN !0,
4 5 ASSIGN !1, 5
5 6 FETCH_CLASS 4 :5 'DateTime'
7 NEW :5
8 DO_FCALL_BY_NAME 0
9 ASSIGN !2,
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
20 QM_ASSIGN_VAR
21 > JMP ->23
22 > QM_ASSIGN_VAR !2
23 > ASSIGN !4,
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 :1
3 DO_FCALL_BY_NAME 0
4 ASSIGN !1,
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 :10
15 SEND_VAL 'P1D'
16 DO_FCALL_BY_NAME 1
17 SEND_VAR_NO_REF 0
18 DO_FCALL_BY_NAME 1
19 QM_ASSIGN_VAR
20 > JMP ->22
21 > QM_ASSIGN_VAR !1
22 > ASSIGN !3,
12 23 > JMP ->8
24 > > RETURN 1
现在,正如您在第二个脚本的操作码中看到的那样,它在每次迭代时都创建了 class 的新实例,并且您创建了一个看似不需要的巨大开销(请参阅 # * 13 - 16
在第二个操作码中),所以首先你要创建完全不必要的新实例,其次这会降低你的性能。
因此,只要您不需要每次迭代都使用全新的 class,第一个脚本更适合您,因为它只创建一次 DateInterval
对象并将其分配给变量.
还有一些额外的信息:
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 的优化和性能方面的知识非常有限。
编辑:看来,我表达得还不够,但我特别要求这样的场景——当创建object returns 静态值,在以下循环中反复使用。
绝对是第一个更快。 N class 个实例比 1 个变量声明更昂贵。
我会选择以下
$dateStep = new DateInterval('P1D');
for($di = 0; $di > $dateInterval; ++$di)
{
$theDate = ($di > 0) $startDate->add($dateStep);
...
}
不建议在循环中一遍又一遍地创建一个对象,除非确实有必要。在上述情况下,对象是在循环之前创建的,并且传递对象可以节省时间(用于创建另一个对象)和 space(通过不在内存中创建另一个对象)。
两个版本在逻辑上是不同的。
第一个版本多次传递同一个对象引用。这意味着如果您在循环后更改 $dateStep
,您将更改引用的 all。
第二个版本在您每次调用该方法时应用对单个对象的引用。
在使用DateTime::add()
方法的例子中,$dateStep
可以看作是一个不变的常量值。在那种情况下,第一个版本更快,更可取,因为它不需要每次都调用构造函数,而且它确实需要更少的内存,因为对象只需要创建一次。
为了从另一个角度来看这个问题,让我们看看脚本和操作码:
脚本 1:
<?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 :0
2 SEND_VAL 'P1D'
3 DO_FCALL_BY_NAME 1
4 ASSIGN !0,
4 5 ASSIGN !1, 5
5 6 FETCH_CLASS 4 :5 'DateTime'
7 NEW :5
8 DO_FCALL_BY_NAME 0
9 ASSIGN !2,
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
20 QM_ASSIGN_VAR
21 > JMP ->23
22 > QM_ASSIGN_VAR !2
23 > ASSIGN !4,
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 :1
3 DO_FCALL_BY_NAME 0
4 ASSIGN !1,
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 :10
15 SEND_VAL 'P1D'
16 DO_FCALL_BY_NAME 1
17 SEND_VAR_NO_REF 0
18 DO_FCALL_BY_NAME 1
19 QM_ASSIGN_VAR
20 > JMP ->22
21 > QM_ASSIGN_VAR !1
22 > ASSIGN !3,
12 23 > JMP ->8
24 > > RETURN 1
现在,正如您在第二个脚本的操作码中看到的那样,它在每次迭代时都创建了 class 的新实例,并且您创建了一个看似不需要的巨大开销(请参阅 # * 13 - 16
在第二个操作码中),所以首先你要创建完全不必要的新实例,其次这会降低你的性能。
因此,只要您不需要每次迭代都使用全新的 class,第一个脚本更适合您,因为它只创建一次 DateInterval
对象并将其分配给变量.
还有一些额外的信息: