By continuing your visit to this site, you accept the use of cookies. Read more

Scout APM helps PHP developers pinpoint N+1 queries, memory leaks & more so you can troubleshoot fast & get back to coding faster. Start your free 14-day trial today .

« back — written by Brent on March 20, 2020

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.

# 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();

# No more uninitialized state

Typed properties in PHP 7.4 can be left uninitialized after construction.

class Foo { public string $bar; public function __construct () { } } $foo = new Foo (); $foo->bar = 'abc' ;

PHP only throws an error when the property is accessed before it's initialised.

$foo = new Foo (); echo $foo->bar;

I'd say to get rid rid of this behaviour. If a typed property isn't initialised after the object was constructed, you get an error.

# Named parameters

Let's allow named parameters to be passed to a function:

function foo ( Bar $bar, string $string, ? int $optional = null) { } foo ( $optional = 1 , $baz = new Baz (), $bar = new Bar (), $string = 'abc' , );

# Multiline short closures

This one doesn't need much explaining.

fn ($a, $b) => { $c = $a + $b; return $a + $b; }

# 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.

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

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

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

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 ;

To end this list: structs. One of my own packages I use all the time is the data transfer object package. It allows us 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.