Disclaimer
This is an advanced post about performance optimization. Don't blindly take this advice. Not all projects prioritize performance. If you are not familiar with the mentioned language features, take your time to understand them.
(1) Know your language constructs
Example
isset($array['key'])
over array_key_exists('key', $array)
Reasoning
Faster than function calls. There are two language constructs that particularly useful, which are isset()
and empty()
.
[Pitfalls] empty()
uses type juggling, see next section.
Opcodes
if(isset($array['key'])) {}
op | return | operands |
---|---|---|
ISSET_ISEMPTY_DIM_OBJ | ~1 | !0, 'key' |
JMPZ | ~1, ->2 |
if(array_key_exists('key', $array)) {}
op | return | operands |
---|---|---|
INIT_FCALL | 'array_key_exists' | |
SEND_VAL | 'key' | |
SEND_VAL | !0 | |
DO_ICALL | $2 | |
JMPZ | $2, ->5 |
(2) Don't fight the type system (but learn it first)
Example
if($arr) {}
over if(count($arr) > 0) {}
Reasoning
Using type juggling reduces redundant opcodes, and therefore also memory allocations.
[Pitfalls] PHP Magic Tricks: Type Juggling presentation by Insomnia Security outlines some example security exploits enabled by inappropriate use of type juggling. Perhaps the most surprising behavior is exhibited in string to integer conversion, e.g. "0e768261251903820937390661668547" == "0"
. This is intentional and well documented.
Opcodes
if($arr) {}
op | return | operands |
---|---|---|
JMPZ | !0, ->1 |
if(count($arr) > 0) {}
op | return | operands |
---|---|---|
COUNT | ~1 | !0 |
IS_SMALLER | ~2 | 0, ~1 |
JMPZ | ~2, ->3 |
(3) Clean up your variables
PHP does some nifty behind-the-scenes optimizations, and this tip is to let it do it’s job. One of the tricks PHP does is related to passing variables by value, rather than reference. PHP will optimize away assignments if the value is not assigned to any other variable, and the value doesn't change.
First example ✔️ -
<?php
$var = 'a';
function a($value) {
echo $value; // do something
}
a($var);
Here the value is assigned in the variable assignment. Even though the value is passed by value, there is actually only one assignment, because the value doesn't change.
Second example ⚠️ -
<?php
$var = ‘b’;
function a($value) {
$value = 'a';
echo $value; // do something
}
a($var);
Here the value changes and therefore there are two assignments, one in the main scope and another inside the function.
Third example ✔️ -
function a($value) {
$value = 'a';
echo $value; // do something
}
a('b');
In this example, the value is assigned just before calling a()
, and since nothing holds reference to it, PHP can mutate the value, instead of making another assignment.
Reasoning
This is not something to worry so much about when the values are small, but I’ve caught some OOM situations where the root cause was an useless variable. This also helps the garbage collector, which only cleans up the values that are not referenced by any variables.
Top comments (4)
I don't agree with some of your points :
isset($array['key'])
overarray_key_exists('key', $array)
isset
don't have the same result thanarray_key_exists
. It also test than the value at the key isnull
. So be careful, you have to know exactly what test you want.(see my post dev.to/klnjmm/5-bad-habits-to-lose...)
isset
andempty
.I don't recommend to use
empty
. It can cause a lot of bugs becauseempty
test that a variable isfalse
. And a lot of values in PHP is considered asfalse
:null
,0
,""
,false
,[]
, ...etc.Instead consider using one of this (you have to know the type of you variable)
Avoid using
empty
function !if($arr) {}
overif(count($arr) > 0) {}
if($arr) {}
makes an implicit cast of$arr
(same problem thanempty
function).If you know that
$arr
is an array, I prefercount
method orif ($arr !== [])
Well, it is your job as a programmer to know when you use which language feature. You can't argue that a function is bad because you can use it incorrectly.
Ok but I think that recommend to other readers (and maybe beginners) to use
empty
function is not a good thing.True, I've added a disclaimer in beginning of the article.
EDIT: And explained the potential pitfalls associated with these optimizations.