In defense of PHP
1673308800

Everyone loves to hate PHP


This hatred is mostly held by people that drink kool aid and don’t really understand the language or the philosophy behind it. The official PHP emblem is an elephant, they should adopt the sheep


Whenever you hear someone criticising PHP incorrectly, please send them a link to this blog and allow me to try and change their mind for you


I defined what really matters when building software so if you are around people that get bogged down by the specific language they use, you should reconsider the people you are spending time with. You want to be around people that Rasmus Lerdorf refers to as a “Z: Hackers“ and if PHP is not the right language for you, then simply use the language you feel is right


Don’t contribute to the invalid criticism



Big companies are using PHP

It’s hilarious to hear people mention that PHP is not used at big companies or at “enterprise scale” when it clearly is


Etsy

“In 2020, Etsy processed $10.28 billion in gross sales, a 106.84% increase from 2019”


USD $10.28 billion ran through their PHP application! Just try and fathom that for a minute. If you don’t feel this is the epitome of an enterprise scale application then I don’t know what is


Etsy is a very good example of what a large-scale PHP application is capable of. What I also find very interesting, and it’s what I learned from listening to a presentation by Rasmus Lerdorf (the original creator of PHP and distinguished software engineer at the company), is that Etsy does not use a mainline PHP framework. Rather, they use a custom MVC framework where the web server rewrites HTTP request URIs to specific front-controllers and they use a custom ORM for database interactions


The tech stack they use is the traditional LAMP stack (Linux, Apache, MySQL and of-course, PHP) so this suggest there is nothing un-capable about using Apache as your web server and MySQL as your relational database (which I’ve already known for years)


Most of the web is powered by PHP

You aren’t going to use PHP to program a spaceship's guidance system or a fuel injector in a large bulk carrier. You’ll use PHP to build the backend of your web application, or web service API, and this is exactly what a lot of people are doing


“PHP is used by 77.3% of all the websites whose server-side programming language we know.”


“...we count the top 10 million websites according to Alexa and Tranco, see our technology overview for more explanations. We do crawl more sites, but we use the top 10 million to select a representative sample…”


This statistic is provided by a company that analyses over 10 million websites and it has found that 77.3% (just under 8 million) of these websites use PHP for the backend processing. I also feel this is a conservative value because my website is not listed in the index and I use PHP. The percentage has declined, considering the previous years statistics, but the decline is not dramatic


PHP also has a very large ecosystem. Frameworks like Laravel have over 30 million downloads, Symfony has over 15 million downloads, so this just contributes to that fact that you’ll probably find PHP somewhere and there is no getting away from the fact that PHP is very well adopted


PHP has come a long way

PHP has its origins as an HTML templating language (with the smallest known Hello World) but it really has come a long way since then. This is very true considering PHP is hardly used for HTML templating any more and there are really great templating engines out there (Symfony Twig, Laravel Blade and mustache, to name a few)


Initially when Rasmus was creating the early editions of PHP, he added features that other people asked for, in an ad-hoc manner, that didn’t even make sense but he did this for them because they did not know how to do this on their own. Rasmus described how this worked in detail in a talk he gave


In today's world, you’ll use PHP for fully-fledged backend processing and very little of this legacy actually remains. PHP also has a formal community around it’s development and very smart people are currently working on the project


Reasons why PHP is good

I’m trying to be as objective as I can


Attempts to reduce complexity

PHP is a dynamic, weakly typed language that offers a lot of flexibility


You’ll be able to rapidly prototype ideas and this concept is extremely important. If you want to test an idea, and see if it’s viable, you’ll use PHP. You’d want the flexibility that the language provides to you and what this basically means is PHP will do guess work on your behalf and will rather run and potentially return the wrong result than not run because you have not thought it through the logic well enough (i.e.: automatic implicit type casting is a good example of the guesswork I’m talking about)


Being dynamic and weakly typed means types are only known at run-time and type collessing can occur, and in fairness, this can lead to bugs. PHP’s answer to the type collessing is type-hinting which is a type-check that occurs at call-time (you hint at the type of function parameters as well as hinting at the return type of the function). This type-check will throw an exception at runtime if the type is not of the expected type


Furthermore, PHP is an interpreted language, so there is no prerequisite compile step. The process of going from human-readable source code to byte/opcodes, which run in the Zend VM, occurs when PHP is invoked, meaning there is no concept of static type-checking in the sense that you can find errors before the code is run. But what you can do is use type-annotations in conjunction with static analysis tools like phpstan or phan that can give you type checking at tool or development time and maybe even one day static analysis will occur during PHP’s dynamic compilation step


You also don’t have to worry about managing memory in PHP. Reference counting occurs in the language so when a region of memory has zero references, it’s automatically cleaned up. PHP has a shutdown sequence that collapses itself and achieves the stateless nature I describe below


All of these concepts attempt to reduce complexity for the developer. Reducing complexity means you can jump into writing business or application logic fairly quickly, and like I said: this is definitely a positive attribute if you are a startup testing an idea or looking for a product-market fit


An interesting thought experiment is contrasting PHP with something like Java or C# and then trying and figure out if either of these languages could solve the problem that Resmus described in this video in as quickly as it needed to be solved (lives were at stake, you don’t have the luxury of planning)


If you use PHP correctly, you won’t need to make any trade-offs later. Just use PHP the correct way


Being single-threaded is positive

PHP typically stands up in a web server and most web servers are multithreaded. Each HTTP request is tied to an individual, single instance of PHP that is invoked either externally in an FPM process or internally in something like mod_php (in Apache’s case)


You wouldn’t want to tie PHP up with long-running, resource intensive tasks because PHP mostly runs on frontend web servers and these types of web servers need to be able to return a result to the HTTP request as quickly as possible. Frontend web server need to keep processing requests


If you need to adopt the asynchronous processing model, you’d involve a queueing mechanism and PHP would typically write a message onto the queue before it sends the response to the client, then you can have your multithreaded backend workers read into this queue and fork all the threads they need (these are often different types of servers that can spend the required time processing the task and they are assigned different amounts of resources; memory, CPU etc)


The front end can then kick off polling on a defined frequency or you could adopt bi-directional communication using something like web sockets. The idea here is that the client does not get the result on the HTTP connection that initiated the processing, it’ll get a result that indicates that it needs to ask again


Being single-threaded also means that globals are not inherently a problem, like they are in some other languages, because globals are not shared across requests (each instance of PHP is thread-safe). It’s very common to have connection objects in the global space (PHP also makes all variables local, by default, to the function they are defined in so you have to explicitly predicate any globals with the ‘global’ language construct)


Another positive attribute of being single-threaded is that you don’t need to worry about race conditions with memory (threads aren’t competing with the same region in memory) nor do you have to worry to much about crashed instances of PHP (the subsequent request will just invoke a fresh instance again)


If someone tries to use PHP being single-threaded as an argument against it, they simply don't understand how the language works and are often trying to get PHP to do something it was simply not designed for


Stateless backends scale horizontally very easily

PHP wants to adopt the properties of the HTTP protocol and one of these properties is being stateless (every request or invocation of PHP has no recollection of the previous invocation) so this means PHP has no concept of server-state (there is no concept of a “PHP application server”)


The state you build into app logic becomes the storage mechanisms issue to scale and manage, not PHP’s. Application logic can make use of a relational database, in-memory cache, file store etc for storing state. With every request that relates to state, the HTTP client must send along all of its relevant cookies (this is very much built into the concept of how the HTTP protocol works) when it performs a request


Because there is no server-state in PHP, it’s very easy to scale horizontally. I’ve worked on many PHP application backends and all of them adopted the horizontal scaling approach, where an application-layer load-balancer (layer-7) would forward an incoming HTTP request to an isolated target underneath it (some load-balancers I’ve implemented are smart in that they track resource metrics on the target machines and don’t just forward HTTP requests in a round-robin way). With this approach, the application was able to process over 100 million HTTP requests in a month


You can contrast this with a stateful backend that will require the request to terminate up against the server that maintains server-state (I haven’t used any server-state that has adopted shared memory across multiple machines or something like thread actors). With this option, you’ll scale vertically and lose all the redundancy and high-availability offered by horizontal scaling


An aside on server-state

There is an interesting way to maintain state within PHP itself—like I’ve implemented on the WebSocket server used by PuBot, and that’s the concept of simply ensuring that the PHP script does not come to an end. You of course would not want to attach this to an HTTP request invoked by the web server but it can be done with the PHP CLI in a separate process and scaling with be vertical


Development workflow is really simple

Write code, save, refresh the browser. You’ll probably have a terminal, with a screen multiplexer like tmux, open and you are tailing the web server logs


PHP provides core functions that are really great for debugging: error_log() writes straight into the web server's error log (hence the name) and you can easily use print_r() to serialise a complex type. All used in conjunction with following the flow I described above


I’ve worked with a Java app that was really quite different. What the typical development flow looked was: write code, save, compile (this process produced a web application archive), copy the web application archive into place, edit an XML configuration file and bump up the version number, reload the Java application server (Apache Tomcat and GlassFish), wait for the reloading to complete, invoke a request


There was no way to use Java’s source-file mode, the WAR archive needed to be compiled and this resulted in a very slow workflow and data was needed from the production database that was not accessible locally


PHP is really fast

You wouldn’t do any task that requires parallel processing (machine learning or fractal image processing etc–often these tasks require processing large, multidimensional arrays of numbers or matrices, where you would want to assign a thread to each dimension in the array), PHP’s processing occurs in series. This is not inherently an issue because…


Modern PHP (7.x, 8.x) ships with:



An aside on threading

There is a PECL library that attempts to get threading to work in PHP named pthreads and there is another library named amphp/parallel but I never had any success with either of these (there is no way to share an object between the threads that are created–sort of makes sense because it’s against how PHP should work)


Reasons why PHP is so-so

I’m purposely using the word “so-so” and not a more harsh word like “bad” because other languages that people actually like, like Python, also have some of these traits


Reference semantics

Objects follow reference semantics and the object references can make changes to the original object. There is no “copy-on-write” for object references like it is with other types


class a {
    private $name = null;

    final public function updateName(string $name): void {
        $this->name = $name;
    }

    final public function getName(): ?string {
        return $this->name;
    }
}

$a = new a();
$a->updateName('Bruce');

/**
 * $b is not a unique instance of $a
 * $b is a reference/pointer/alias to the already existing $a
 */
$b = $a;

print $b->getName() . PHP_EOL;


Function parameters (pass by reference) and function return values (return by reference) can also use reference semantics but doing this is a little more conscious (you have to predicate the parameters with an ampersand)


Reference semantics and using pointers can often lead to bugs when the code base becomes large. Usually you’ll be at this stage when it’s not possible to understand the entire code-base and you’ll start to perform experiments instead of familiarising yourself with the entire codebase


Single inheritance

An object can only have a single base class (there is multiple inheritance of interfaces in PHP, like pretty much all other languages)


You can achieve something similar to multiple inheritance using traits. Traits are horizontal code reuse and they are usually implemented when the vertical inheritance model does not fit


class awesome implements interfaceA, interfaceB {
  use traitA, traitB;
}


No block scope

Variables used on any type of iterative loop (for, for-each, while) or defined within the block itself can all be available outside of the block (with the final assignment being the variable value). It’s exactly the same with any statement that uses blocks (if/else etc)


$names = array('PersonA', 'PersonB', 'PersonC');
$name  = 'Bruce';

foreach ($names as $name) {}

print $name . PHP_EOL;


Contrast this with a language that supports block-scoping (in this case: JavaScript)


var name  = 'Bruce';
var names = ['PersonA']
for (let name of names) {}
console.log(name);


You’ll need to be extra sure that you don’t reference the final state of the variable by accident


Why not Python

Python is great


It’s also a dynamic, weakly typed language but Python can be used for other system related work and not exclusively for the web


Python also has mypy for static-type checking (the type-annotations are reserved syntax and are omitted by Python)


PHP can interact with a lot more database servers than what Python can but I’m not making an argument against Python, both PHP and Python are really great


Why not Node.js

JavaScript on the backend is really great and with Node.js, TypeScript is supported so you can get static-type checking. TypeScript will need to be transpiled to JavaScript


Node.js has Express, which makes it really easy to map HTTP request URIs to callback functions