3 tips for performant PHP code
Tags: php
Published: 2020-07-07 13:32:29

---
title: 3 tips for performant PHP code
published: true
description: 
tags: php
//cover_image: https://direct_url_to_image.jpg
---

## 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()`](https://www.php.net/manual/en/function.isset.php) and [`empty()`](https://www.php.net/manual/en/function.empty.php).

[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](https://www.php.net/manual/en/language.types.type-juggling.php) reduces redundant opcodes, and therefore also memory allocations.

[Pitfalls] [PHP Magic Tricks: Type Juggling](https://owasp.org/www-pdf-archive/PHPMagicTricks-TypeJuggling.pdf) 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](https://www.php.net/manual/en/language.types.string.php#language.types.string.casting).

### 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
<?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
<?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 ✔️ -

```php
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.