Constrain your classes with PHPStan

In this post I will show how you can leverage PHPStan to constrain your existing classes for better type safety. This may sound abstract at first, but I do have a particular application in mind that I want to showcase.

Let me set the background for you:

I am building an ecommerce application. It has various entities like products, orders, invoices, customers, and addresses which are related to each other.

Examples:

  • A customer has zero or more addresses.
  • An address belongs to a single customer.
  • A customer has zero or more orders.

My goal is to represent entities and relations in PHP in a type-safe manner. In particular, I want to be able to represent selectively loaded relations in the type system. For example, a type for “customer with loaded addresses but without orders” which can be statically checked with PHPStan.

Continue reading “Constrain your classes with PHPStan”

PHP now has support for undefined!?

Before you dismiss this post as some cheap clickbait, please take a look at the following code and tell me if this is PHP:

<?php

function greeting(string $name, string|null|undefined $title = undefined) {
    $greeting = 'Hello';
    $greeting .= match ($title) {
        null => ' ',
        undefined => ' ??? ',
        default => " $title ",
    };
    $greeting .= $name;
    return $greeting;
}

echo greeting('John Doe');

Drumroll… it actually is perfectly valid PHP code.

Continue reading “PHP now has support for undefined!?”

Constants are no longer constant in PHP

I really hope that I am not opening a can of worms here because I think I have found something in PHP that I should not have. Something that should not exist: const mutable objects.

Yes, you read that correctly. Since PHP 8.1, any regular old object can be a constant, even mutable ones. Why is this a big deal? Well, because constants used to be constant and never change. This is no longer the case.

Here, have a quick taste:

<?php

class MyClass {
    public int $value = 1;
    public function set(int $value) { $this->value = $value; }
}

const MY_OBJECT = new MyClass();
// Equivalent to:
// define('MY_OBJECT', new MyClass());

echo MY_OBJECT->value . "\n";
MY_OBJECT->set(2);
echo MY_OBJECT->value . "\n";

// Prints:
// 1
// 2

Interesting.

Continue reading “Constants are no longer constant in PHP”

Elegant immutable object pattern in PHP

As many of you know, immutability is an extremely useful concept that makes code more predictable and generally easier to understand. Case in point, in PHP we have the mutable DateTime as well as DateTimeImmutable, the latter being recommended over the former.

And why is that?

Well, being an immutable object means that it can be passed around fearlessly without worrying about someone mutating it. No more guessing whether you should make a defensive copy or not. Plus, the API of DateTimeImmutable is not any worse than that of DateTime, so you get all of the benefits basically for free.

But it does not stop with DateTimeImmutable. We were always able to write our own immutable class types in PHP, and with the recently introduced readonly properties (PHP 8.1) and readonly classes (PHP 8.2) it is now easier than ever.

Continue reading “Elegant immutable object pattern in PHP”

Laravel shorts – Old inputs are still inputs

If you need some inspiration for designing a 500 error page, all you need to do is to find a stylish site that is built on Laravel and navigate to its login page. Then you open up the developer tools and change the name attribute of the email input field from email to email[]. Enter some random credentials and submit.

Disclaimer: Doesn’t work on all Laravel sites and the example isn’t all that pretty. If you actually did manage to log into someone’s account, don’t do anything silly.

Continue reading “Laravel shorts – Old inputs are still inputs”

Laravel shorts – Blade component gotcha

Update 2021-10-22
An issue has been created on GitHub: https://github.com/laravel/framework/issues/39232

And a fix has been merged:
https://github.com/laravel/framework/pull/39319


Blade components are a great tool for structuring your view templates into small reusable pieces. But while working with them, I stumbled upon a gotcha that I think you should know about. First, let’s take a look at this anonymous component:

post-title.blade.php

@props(['post'])
<h1 {{ $attributes }}>{{ $post->title }}</h1>

And here is how it is used in, say, a post list page:

@foreach ($posts as $post)
  <x-post-title :post="$post" />
@endforeach
Continue reading “Laravel shorts – Blade component gotcha”

Detecting cyclic arrays in PHP – A new approach

Part 2 of series Detecting cyclic arrays in PHP.

In Part 1 of this series I explained the problem of detecting cyclic arrays, and why it cannot be done in pure PHP. I also promised to present a solution that is both simple and correct for all possible arrays, which is what this post is about. But before that, let me restate the definition of cyclic arrays from the previous post: An array is cyclic if iterating all of its items and subitems does not terminate.

Here is an example of a cyclic array:

$array = [1, [2, 3]];
$array[1][1] = &$array;
Continue reading “Detecting cyclic arrays in PHP – A new approach”

Why it is impossible to detect cyclic arrays in pure PHP

Part 1 of series Detecting cyclic arrays in PHP.

This post is about a problem that might only be relevant to a small minority of PHP programmers who maybe want to write a custom serializer, or something else that requires recursively iterating an array. But, in trying to solve it, I found some interesting PHP weirdness that I think is worth highlighting.

As an aside:
If you are just looking for a reliable solution for detecting cyclic arrays – and you want to miss out on learning about some cool (but also complicated) PHP quirks – then skip to Part 2 of this series.

First of all, let’s define our terms. For the purpose of this post, we can espouse a very pragmatic definition: An array is cyclic if iterating all of its items and subitems does not terminate. Cyclic arrays are also sometimes called circular or recursive. Let’s look at some examples:

// Contains a reference to itself
$v = [1, 2, 3];
$v[1] = &$v;

// Contains a nested array that contains a reference to $x
$x = [1, [2, 3]];
$x[1][1] = &$x;

// Contains a nested array that contains a reference to an ancestor
$y = [1, [2, [3, 4]]];
$y[1][1][1] = &$y[1];

// Contains a nested array that contains a reference to itself
$z = [1, [2, 3]];
$z[1][1] = &$z[1];

I think you get the idea. All of these arrays contain a cycle at some level.

Continue reading “Why it is impossible to detect cyclic arrays in pure PHP”