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”

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”