If you enjoy reading my blog, you could consider supporting me on Patreon.

PHP reimagined

This post is simply me thinking about how we could change PHP to make it better. It's a very subjective list, and in no way a critique on the amazing work the core team is doing.

# Final by default

A common misconception about OO programming is that it's all about inheritance. Inheritance and polymorphism have their place, but OO is way more than that.

Because these principles are more often than not abused by programmers who claim they write "OO" code, I think the language should help prevent us making these mistakes.

That's why I would make all classes final by default:

final class Foo
{
}
class Bar extends Foo
{
}

Furthermore: classes are only allowed to extend from abstract classes or implement interfaces. This way we can prevent deep inheritance chains of concrete classes.

# Void by default

Void is such a strange beast in all programming languages: it a "type", indicating the lack of a type.

Why not go with the obvious way: no return type, means nothing is returned.

class Foo
{
    public function bar(): void
    {
        // …
    }
}
class Foo
{
    public function bar()
    {
        return false;
    }
}

Now you might be thinking: what if a function wants to return two types, that's the next point.

# No mixed type

The mixed type basically means: "you've got no idea what this function needs or will return, figure it out on your own".

Such a loose type system can be the source of many bugs. If you feel the need to use two different types in the same function, you should either make two implementations — this is where polymorphism has its place; or you should program to an interface.

Either way, there's always a better solution then relying on mixed. In my version of PHP, the language would ensure we always choose the better solution.

# No method overloading

It's a common feature request for PHP: having several definitions for the same method. My argument against it ties directly to the previous one: there's a better solution to fix this problem.

If you feel the need for a method having two implementations, you should look at polymorphism or program to an interface.

class Foo
{
    public function handle(Bar $bar) { /* … */ }
    
    public function handle(Foo $bar) { /* … */ }
}

# All parameters must by typed

We already established that my version of PHP would make return types required. It's no surprise that the same goes for function parameters.

public function handle($bar)
{
}
public function handle(Bar $bar)
{
}

# Class properties must be typed

The same rules apply to class properties. Luckily for us, PHP 7.4 will introduce typed properties. I'd make them required though.

class Foo
{
    public $bar;
}
class Foo
{
    public Bar $bar;
}

# Visibility modifiers are required

Explicitness eliminates room for confusion. That's why all methods and class variables must have a visibility modifier.

class Foo
{
    function bar()
    {
        // …
    }
} 
class Foo
{
    public function bar()
    {
        // …
    }
} 

# Final on variables

I started this list by saying I'd drop the final keyword, that is on classes and methods. final would be a valid keyword to mark class variables as "read only".

A final variable may be set on construct, and not be changed afterwards.

class Foo
{
    public final Bar $bar;
    
    public __construct(Bar $bar)
    {
        $this->bar = $bar;
    }
}
$foo = new Foo($bar);

$foo->bar = new Bar();

# Scalar types are also objects

One of the few things I think that we're all in agreement about: the current PHP function names and definitions are inconsistent and kind of sucky.

Let's treat all scalar types as objects, allowing them to contain what otherwise would be standalone functions.

public function handle(): String
{
    return "a, b, c";
}

$this->handle()->explode(',');

# Improved variance

You may have noticed a trend in the above changes. Most of them relate to PHP's type system. If all them were added, we'd also need to make the current type system more flexible.

Luckily again, PHP 7.4 already introduces improvements regarding type variance.

class Bar extends Foo { /* … */ }
interface A
{
    public function handle(Bar $bar): Foo;
}

class B implements A
{
    public function handle(Foo $bar): Bar
    {
        // …
    }
}

# Always strict type checking

Strict type checking is done by default, you should never declare(strict_types=1); anymore.

# Generics

After several improvements to the type system, I'd add some more improved ways to actually use is.

First a feature that probably most of the PHP world is waiting for: generics.

class List<T>
{
    public function current(): T
    {
        // …
    }
}

# Enums

Next up: built-in enums. Based on the several userland implementations it's clear that the community would benefit from a built-in enum type.

enum Status 
{
    DRAFT, STATUS, PUBLISHED;
}
class Bar
{
    public Status $status;
}
$bar->status = Status::DRAFT;

# Structs

The end this list: structs. One of my own packages I use all the time is the data transer object package. It allows to define strongly typed objects. In essence, they are a userland implementation of what structs are meant to solve.

struct Point {
    Int $x;
    Int $y;
}
$point = Point {1, 2}

# This is Java!

That's something I hear PHP programmers say quite often when improvements to the type system are proposed. Remember that a programming language is more than its syntax though: there's a whole ecosystem of frameworks and packages that gives a language like PHP its real value.

This is where the ad would go. I get it, they are stupid. But to be honest, they actually make a difference. So maybe you'd consider whitelisting this blog or support me on Patreon?