- URL: https://www.laruence.com/en/2009/04/24/695.html
- Please include attribution when republishing.
I've seen many people who, when working with arrays, don't quote the non-numeric key names:
$array[key] = $value;
I can understand that some people might find such code "tidy", and it does run fine.
Even more so, if they are "lucky" enough to have PHP configured like this:
error_reporting = ~E_NOTICE
they may forever stay immersed in their "tidy" style, never seeing any NOTICE, and never realizing how much performance they lose by doing this.
Come, let's look at it together:
good.php:
<?php
$array = array();
$i = 0;
while(++$i < 1000){
$array['good'] = 2;
}
?>
bad.php:
<?php
$array = array();
$i = 0;
while(++$i < 1000){
$array[good] = 2;
}
?>
Now look at the run times (averaged over multiple runs):
With quotes:
$ time php -f good.php real 0m0.013s user 0m0.005s sys 0m0.007s
Without quotes:
$ time php -f bad.php PHP Notice: Use of undefined constant bad - assumed 'bad' in /home/huixinchen/tmp/bad.php on line (999 lines of NOTICE omitted here) real 0m0.100s user 0m0.020s sys 0m0.029s
See how big the difference is?
Oh, perhaps we should simulate the situation of those "lucky" people — remove the overhead spent recording the NOTICE, and see.
$ time php -f bad.php real 0m0.037s user 0m0.018s sys 0m0.018s
We can see that, basically, the efficiency loss between using quotes and not using quotes is more than threefold.
So where does this efficiency loss go?
Let's look at the OPCODE sequences generated by the two files:
good.php :
filename: /home/huixinchen/tmp/good.php
compiled vars: !0 = $array, !1 = $i
line # op fetch ext return operands
-------------------------------------------------------------------------------
2 0 INIT_ARRAY ~0
1 ASSIGN !0, ~0
3 2 ASSIGN !1, 0
4 3 PRE_INC $3 !1
4 IS_SMALLER ~4 $3, 1000
5 JMPZ ~4, ->9
5 6 ZEND_ASSIGN_DIM !0, 'good'
7 ZEND_OP_DATA 2, $6
6 8 JMP ->3
8 9 RETURN 1
10* ZEND_HANDLE_EXCEPTION
bad.php :
filename: /home/huixinchen/tmp/bad.php
compiled vars: !0 = $array, !1 = $i
line # op fetch ext return operands
-------------------------------------------------------------------------------
2 0 INIT_ARRAY ~0
1 ASSIGN !0, ~0
3 2 ASSIGN !1, 0
4 3 PRE_INC $3 !1
4 IS_SMALLER ~4 $3, 1000
5 JMPZ ~4, ->10
5 6 FETCH_CONSTANT ~5 'bad'
7 ZEND_ASSIGN_DIM !0, ~5
8 ZEND_OP_DATA 2, $7
6 9 JMP ->3
8 10 RETURN 1
11* ZEND_HANDLE_EXCEPTION
We can see (and indeed the NOTICE tells us as much) that PHP treats an unquoted key name as a constant to be fetched; when it can't find one, it throws a NOTICE, then generates a string from the "constant name", and continues using that string as the key.
You, being clever, will surely realize this can lead to the following unpredictable error:
define('key_name' , 'laruence');
....
//many lines of code omitted
$array[key_name] = 2; //becomes $array['laruence'] = 2;
//An error like this would leave you quite puzzled, wouldn't it?
Get it? Non-numeric key names in arrays must always be quoted.
Oh, I remember some people will say that when interpolating in a double-quoted string, writing quotes causes an error.
Well, the standard way to write it:
$string = "variable value is {$array['key']}"
I'm all for "be lazy" — but being lazy should still have its principles.
Finally, good code should not be disguised by turning off error_reporting.
As a footnote, here is the relevant logic in the FETCH_CONSTANT OPCODE for when the constant isn't found:
....
if (!zend_get_constant(opline->op2.u.constant.value.str.val,
opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
opline->op2.u.constant.value.str.val,
opline->op2.u.constant.value.str.val);
EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;//get the "constant" name string
zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);//allocate space, generate the string
}
....
Be First to Comment