100 Languages Speedrun: Episode 56: PHP
Tags: php
Published: 2022-01-15 13:05:15

PHP is trash. But you probably knew that already. Let's see just how trash is it.

### Hello, World!

Here's the Hello, World! in PHP:

```
Hello, World!
```

```
$ php hello.php
Hello, World!
```

PHP hates itself so much, it won't even run PHP code unless you explicitly make it. It would much rather pretend it doesn't exist.

Anyway, let's force it to run some code:

```php
<?php
echo "Hello, World!\n";
?>
```

```
$ php hello2.php
Hello, World!
```

### Unicode

We can start with the standard check of language quality, Unicode support. Unsurprisingly PHP completely fails at it, because the language is trash:

```php
<?php
echo strlen("Hello"), "\n";
echo strlen("Żółw"), "\n";
echo strlen("💩"), "\n";
echo strtoupper("Żółw"), "\n";
?>
```

```
$ php unicode.php
5
7
4
ŻółW
```

But if you prefix all string functions with `mb_`, they work:

```php
<?php
echo mb_strlen("Hello"), "\n";
echo mb_strlen("Żółw"), "\n";
echo mb_strlen("💩"), "\n";
echo mb_strtoupper("Żółw"), "\n";
?>
```

```
$ php unicode2.php
5
4
1
ŻÓŁW
```

I think this really sums up PHP. PHP does something stupid. Instead of fixing it and potentially breaking backwards compatibility, they leave the stupid thing there, and introduce the new fixed thing.

For example `mysql_escape_string` it used to protect from SQL injection was completely insecure. Did PHP fix it? Obviously not, it introduced `mysql_real_escape_string` that doesn't have this particular issue.

If you want to see PHP do stupid things, just pick a standard library function at random, the chance is pretty good it has a fixed version somewhere, but they left the broken one behind.

### Equality

We all keep making fun of JavaScript because of its broken `==`, but somehow PHP `==` is a lot worse.

Take a guess what this script is going to print. I bet you'll fail at it:

```php
<?php
  function compare($a, $b) {
    if ($a == $b) {
      echo "$a == $b\n";
    } else {
      echo "$a != $b\n";
    }
  }

  compare("wtf", true);
  compare("wtf", 0);
  compare(true, 0);
  compare("wtf", 1);
  compare(true, 1);
  compare(true, 69);
  compare(false, 0);
  compare(false, array());
  compare(0, array());
?>
```

```
$ php equality.php
wtf == 1
wtf == 0
1 != 0
wtf != 1
1 == 1
1 == 69
 == 0
 == Array
0 != Array
```

What the fuck is even going on here. JavaScript does some automatic type conversions, but this, like what is even.

To make matter worse, PHP has string interpolation, but it does the weirdest things - `true` becomes `1` (so `1 == 69`), `false` becomes empty string, array with any content becomes string `Array`. Like what?

### Triple Equals

What did PHP do? The same thing as JavaScript, they added `===`, which doesn't do any of those things:

```php
<?php
  function compare($a, $b) {
    if ($a === $b) {
      echo "$a === $b\n";
    } else {
      echo "$a !== $b\n";
    }
  }

  compare("wtf", true);
  compare("wtf", 0);
  compare(true, 0);
  compare("wtf", 1);
  compare(true, 1);
  compare(true, 69);
  compare(false, 0);
  compare(false, array());
  compare(0, array());
?>
```

```
$ php equality2.php
wtf !== 1
wtf !== 0
1 !== 0
wtf !== 1
1 !== 1
1 !== 69
 !== 0
 !== Array
0 !== Array
```

Of course it wouldn't be PHP if it was actually working. It deals with arrays correctly (as far as I can tell), but with objects, it's only `===` in case of identity.

```php
<?php
  class Vector {
    public $x, $y;
    public function __construct($x, $y) {
      $this->x = $x;
      $this->y = $y;
    }
  }

  function compare($a, $b) {
    $aj = json_encode($a);
    $bj = json_encode($b);
    if ($a === $b) {
      echo "$aj === $bj\n";
    } else {
      echo "$aj !== $bj\n";
    }
    if ($a == $b) {
      echo "$aj == $bj\n";
    } else {
      echo "$aj != $bj\n";
    }
  }

  $a = array(1);
  $b = array(1);
  $c = array("1");

  $d = new Vector(1, 2);
  $e = new Vector(1, 2);

  compare($a, $b);
  compare($a, $c);

  compare($d, $d);
  compare($d, $e);
?>
```

```
$ php equality3.php
[1] === [1]
[1] == [1]
[1] !== ["1"]
[1] == ["1"]
{"x":1,"y":2} === {"x":1,"y":2}
{"x":1,"y":2} == {"x":1,"y":2}
{"x":1,"y":2} !== {"x":1,"y":2}
{"x":1,"y":2} == {"x":1,"y":2}
```

### Ternary Operator

PHP is such trash, they managed to get wrong something that as far as I know no other language in history managed to get wrong.

Take a wild guess what this will do:

```php
<?php
  function compare($a, $b) {
    echo ($a > $b) ? "$a > $b" : ($a < $b) ? "$a < $b" : "$a == $b";
    echo "\n";
  }

  compare(420, 69);
  compare(69, 69);
  compare(69, 420);
?>
```

Was this what you thought?

```
$ php ternary.php
420 < 69
69 == 69
69 < 420
```

### FizzBuzz

Nothing unusual here. Only having C style `for` loops instead of ranges is not great, but it's not even in top 100 of PHP design fails:

```php
<?php
for ($n = 1; $n <= 100; $n += 1) {
  if ($n % 15 == 0) {
    echo "FizzBuzz\n";
  } else if ($n % 5 == 0) {
    echo "Buzz\n";
  } else if ($n % 3 == 0) {
    echo "Fizz\n";
  } else {
    echo "$n\n";
  }
}
?>
```

### Fibonacci

This code is not the worst:

```php
<?php
function fib($n) {
  if ($n <= 2) {
    return 1;
  } else {
    return fib($n - 1) + fib($n - 2);
  }
}
for ($n = 1; $n <= 20; $n += 1) {
  echo "fib($n) = " . fib($n) . "\n";
}
?>
```

### Should you use PHP?

No. The language is trash. Everything about it is bad. Use pretty much anything else.

This episode was a little taster of all that's wrong with PHP. The deeper you go, the worse it gets.

People often compare PHP with Perl or JavaScript, but PHP is such a unique trash pile of terrible language design, it's like it was created specifically to make JavaScript developers feel better about their language. And Perl for all its unusual choices really had its weird internal logic.

It was only by a weird quirk of history, involving `mod_php` and free and cheap shared hosting providers, that PHP became popular back in the days. None of these reasons apply anymore. Kill it with fire.

### Code

[All code examples for the series will be in this repository](https://github.com/taw/100-languages-speedrun).

[Code for the PHP episode is available here](https://github.com/taw/100-languages-speedrun/tree/master/episode-56-php).