DEV Community

Tyler Smith
Tyler Smith

Posted on • Edited on

Is PHP a gnarly language? Yes, yes it is.

Today I saw a tweet asking why developers dislike PHP. This was a question that I asked frequently during my first two years as a PHP developer. Now that I've worked primarily in JavaScript for over a year, I feel like it may be helpful if I write down my personal gripes with PHP so it isn't a mystery.

PHP uses inconsistent naming

In Python, objects are typically StudlyCase, and nearly everything else is snake_case. In JavaScript, objects are StudlyCase, and almost everything else is camelCase.

In PHP, naming isn't predictable. For example: the substr_replace() function has an underscore between the two words. Because of this, you might assume that PHP would follow this pattern for a function that makes a string lowercase, maybe naming the function something like str_to_lower().

You'd be wrong: in PHP this function is strtolower(), which has no underscores between the words.

If you want to get a row from your SQL query response in PHP, you use the snake case $response->fetch_assoc() method. However, if you want to implement the ArrayAccess interface on a class, you must use camel case methods like offsetGet().

I find myself having to constantly do Google searches for basic PHP language functions because the patterns aren't predictable.

PHP has inconsistent function signatures.

PHP is famous for having inconsistent function signatures, which means similar functions take their arguments in a different order. Let's look at array_map().

$lowercase_names = array_map(function($name) {
  return strtolower($name);
}, ["Jim", "Todd"]);
Enter fullscreen mode Exit fullscreen mode

The array_map() function takes a function as its first argument and array as its second argument. You might expect array_filter() would take its arguments in the same order, but again you'd be wrong.

$even_numbers = array_filter([1, 2, 3, 4, 5], function($number) {
  return $number % 2 === 0;
});
Enter fullscreen mode Exit fullscreen mode

The arguments have flipped. I'd argue that this is bad language design.

PHP's array datatype does too much.

PHP's array datatype stores both one-dimensional arrays (["apple", "orange", "potato"]) and key => value arrays (["name" => "Jim", "favorite_color" => "red"]). In JavaScript, these would be two separate data structures: an array and an object literal. In Python, these would also be two different data structures: a list and a dictionary.

Under the hood, PHP actually stores one-dimensional arrays as two-dimensional arrays, with the values' keys implicitly assigned upon creation. This means when you create the array ["apple", "orange", "potato"], PHP actually stores it as [0 => "apple", 1 => "orange", 2 => "potato"].

These implicit keys can lead to interesting and unexpected behavior. Consider an example where you have a list of people's names and favorite colors. Now let's say you want to filter the list down to people whose favorite color is blue, and then get the first person in the filtered list. You might write the following PHP.

<?php

$people = [
  ["name" => "Jim", "favorite_color" => "red"],
  ["name" => "Pam", "favorite_color" => "blue"],
  ["name" => "Michael", "favorite_color" => "blue"]
];

$people_who_like_blue = array_filter($people, function($person) {
  return $person["favorite_color"] === "blue";
});

var_dump($people_who_like_blue[0]);
// Undefined offset: 0 in array_filter_test.php on line 13
Enter fullscreen mode Exit fullscreen mode

The var_dump() in this example displays an undefined offset. You might expect it to return "Pam", because she is the first person who likes the color blue (again: you'd be wrong). However, when you dump the contents of the $people_who_like_blue array, you might see the problem.

array(2) {
  [1]=>
  array(2) {
    ["name"]=>
    string(3) "Pam"
    ["favorite_color"]=>
    string(4) "blue"
  }
  [2]=>
  array(2) {
    ["name"]=>
    string(7) "Michael"
    ["favorite_color"]=>
    string(4) "blue"
  }
}
Enter fullscreen mode Exit fullscreen mode

PHP's one-dimensional arrays have implicit keys, so when you run array_filter(), the result still retains the original implicit keys. There is no array item at $people_who_like_blue[0] because the first array key is actually 1.

If PHP had a one-dimensional array primitive like JavaScript's array datatype or Python's list datatype this wouldn't be an issue.

Manipulation of primitives is done through functions instead of methods.

This one is purely a matter of preference, but I prefer JavaScript's methods for manipulating strings and numbers (myString.toLowerCase()) over PHP's functions for manipulating its primitives (strtolower($my_string)).

Why do I prefer methods over functions? Because autocompletion works better with methods than with functions if you don't know exactly what you're looking for. That means I don't have to remember as much because the computer will remember it for me.

PHP's official documentation is challenging.

While not necessarily a knock on the language itself, I find php.net's documentation really difficult to understand. A lot of the information that's critical for new coders to understand PHP concepts isn't in the documentation itself, but in user-submitted comments below the docs which can be up and down-voted Stack Overflow style. I found the PHP docs to be the worst place to learn PHP.

When you contrast this to how comprehensive Python's official documentation is, it's a stark difference.

PHP is dynamically typed.

Dynamic typing is a PHP feature, not a bug. It's also one of the language's most powerful tools: implicit types just work, and you can use PHP's magic methods to create class methods out of thin air.

While this is powerful, it's not always predictable. Autocomplete and your editor won't always be able to help you: you need to keep more in your head, and it creates the potential for more bugs.

PHP's advanced object-oriented features are an awkward fit.

PHP borrowed some advanced object-oriented features from languages like Java, such as interfaces, abstract classes, and private methods. These features allow for some powerful patterns that aren't possible in JavaScript/Python/Ruby, but without better support for static types it feels like a half measure.

So is PHP all bad? Absolutely not!

Despite my issues with PHP, Laravel is currently my favorite backend framework. The collections class and string helpers in Laravel completely mitigate many of the issues with PHP I've listed. Laravel's batteries-included approach lets me build production applications more rapidly than I could ever hope to in Node.js.

PHP also powers over three-quarters of the web. WordPress–a popular content management system built with PHP–powers almost 40% of the top million websites. With affordable hosting and one-click WordPress installs, PHP has democratized a web that is filled with walled gardens like Facebook, and it ensures that every voice has a chance to be heard online. PHP also powers much of Facebook, which shows that it is still a serious development platform in 2020.

Despite all of PHP's warts, it is the universal language of the web and ultimately a force for good.

Top comments (0)