Let's not go down the PHP is dead, long live PHP rabbit hole that seems permeates public perception of this language.

We've all read a a fractal of bad design.

We've all probably worked on Wordpress.

Some of us might have dabbled in Hack.

PHP 7 is everything apparently.

So it goes...

Brief history

Things have definitely changed over the years. I remember my first days of writing code in PHP. Lots of globals, mixed view logic, spaghetti everywhere, un-sanitized inputs, etc... A lot of stuff that beginners have absolutely no concept of.

PHP doesn't care though, it lets you use it as you see fit.

It is so incredibly easy to get a page to print stuff with this language. Fire up a web-server, write some quick HTML mixed with <?php tags, and you were living life in the fast lane. Dreams of building your one-of-a-kind startup idea PHP start to eat at you. Other languages bore you with their strict rules on indentation or types. You just want to write it quick and build it now.

This is exactly what caused PHP to have such a negative connotation. Low barrier of entry.

Everyone makes this point but its true. Its mad easy to just hack together a PHP script and have it print stuff out. We even refer to them as scripts; not programs or software. This is where PHP has lost its grace as a "mature" language.

Ch-ch-ch-ch-changes

Since the early 2010's loads of important companies and individuals have put incredibly arduous and admirable work to clean up this languages reputation.

  • Frameworks have helped; driving force that has led to widely adopted standards.
  • Facebook helped; HHVM and Hack were a great fire for the languages core contributors.
  • PHP 7 helped; type hinting, typed return values, amazing performance gains. Love it.
  • The community helped; pushed back and started informing/purging net of bad resources.

The fact of the matter is you can build successful products and businesses on PHP.

Are there detractors? Yeah. I have had countless engineers tell me that its impossible to build a stable business on PHP. They cite language concerns, a shrinking talent pool, and slow runtimes.

Each in their own right a valid criticism.

But this is old news. Every language you ever use will have these sentiments. Perhaps its not just the language; maybe its you?

If you can't find a way to write good code in a language maybe its your review process or manifesto.

If you can't find talent maybe its your culture or branding.

If you have slow PHP apps maybe its your code or your infrastructure.

Point being there is no equality with these arguments and its pointless to make blanket criticisms of something that has way too many independent variables to measure. I will always respond to and acknowledge the criticisms put forth to a language I use but I will not participate in almost religious conquest against language/tooling I might not enjoy working with.

What its like now

I'll post a few snippets of things I've been writing here and comment on them, to show you what "modern" PHP might look like.

Disclaimer: some code features helpers from frameworks. Frameworks or libraries are usually part of your day-to-day coding. Deal with it.

public function receive(WebhookRequest $request) : JsonResponse  
{
    $topic = $request->get('x-webhook-topic');

    event(Events\WebhookRequestReceived($topic));

    $webhook = $this->webooks->findByTopic($topic);

    $arn = "Events\{$webook->class}";

    if (class_exists($arn)) {
        event($arn);

    } else {
        event(Events\WebookEventMissing($webhook));

        abort(500); // or throw new Exception
    }

    event(Events\WebookRequestFinished($webook));

    return response()->json(['message' => "Webhook {$topic} finished processing."]);
{

Simple method that recieve's webhooks. Some behind the scenes stuff handled by framework include:

  • Auto-validating the request; e.g WebhookRequest has certain rules, such as the header for the topic, and will fail the request.
  • event() and response() helpers. They do what you think they do.
    public function install(Shop $shop) : array
    {
        $api = $this->apiFactory->makeApi($shop->access_token, $shop->url);

        $services = $this->fulfillmentService($api);

        $hooks = $this->registerWebhooks($api);

        return ['services' => $services, 'webhooks' => $hooks];
    }

    private function fulfillmentService(Client $api) : array
    {
        $serviceConfig = config('shop.fulfillment_service');
        $response = $api->get('/admin/fulfillment_services.json');
        $existing = null;

        foreach ($response['fulfillment_serices'] as $service) {
            if ($service['handle'] === $ourHandle) {
                $existing = $service;
            }
        }

        $request = ['fulfillment_service' => $serviceConfig];

        if ($existing) {
            $response = $api->put(
                "/fulfillment_services/{$existing['id']}.json", 
                ['form_params' => $request]
            );

        } else {
            $response = $api->post(
                '/fulfillment_services.json', 
                ['form_params' => $request]
            );
        }

        return $response;
    }

    private function webhooks(Client $api) : array
    {
        $webhooks = config('shop')['webhooks'];
        $registered = $api->get('/admin/webhooks.json');

        $findExisting = function ($existing, $webhook)
        {
            $found = array_filter($existing, function ($i) use ($webhook)
            {
                return $i['topic'] === $webhook['webhook']['topic'];
            });
            return array_shift($found);
        };
        $saved = [];

        foreach ($webhooks as $webhook) {
            $existing = $findExisting($registered['webhooks'], $webhook);

            if (array_get($existing, 'id')) {
                $response = $api->put(
                    "/webhooks/{$existing['id']}.json", 
                    ['form_params' => $webhook]
                );

            } else {
                $response = $api->post(
                    '/webhooks.json', 
                    ['form_params' => $webhook]
                );
            }

            $saved[] = $response;
        }

        return $saved;
    }
}

Some code that hits an API and does some configuration.

  • A few more framework helpers config() and array_get().
class MessageParser {

    private $messages;

    public function __construct(array $messages)
    {
        $this->messages = $messages;
    }

    public function route()
    {
        $messages = [];
        $namespace = 'Messages';

        foreach($this->messages as $payload) {
            $payload = key($payload);
            $params = $payload[$message];

            if (!is_array($params)) {
                throw new InvalidArgumentException;
            }

            $className = "{$namespace}\\{$message}";

            if (!class_exists($className)) {
                throw new InvalidArgumentException;
            }

            $messages[] = new $className(...$params);
        }

        return $messages;
    }
}
  • No framework helpers here!

So wat?

Other the ranting the goal here was just to collect my thoughts on the progression of PHP and where it stands as a language today.

I chose these examples because they are code I have written lately for production apps.

Yeah there's a lot of framework boiler plate in these examples. So what? Every language has a stdlib. PHP's stdlib kinda sucks. We still leverage frameworks and libraries to turn the language off from that "easy entry, low quality, insecure" nightmare you find on Google.

I care about readability, maintainability, security.

I care about products and customers.

I care about language features.

I care about tooling and frameworks.

I don't care what language you use to ship software.

I don't blindly follow dogma or stigma.

At the end of the day we have jobs. We write code that provides an emotional or monetary benefit to ourselves and/or others. Do I think its limiting to only ever write in one language? Yes. Can you make a successful career as a software engineer ever only writing one language? Yes. Should you? Probably not.

Cheers