Reading The Art of Modern PHP 8 (part 2)

In my reading of the PHP OOP Manual, I ended up pretty far afield.

Somehow I got to Crell's blog (although I think that was by way of another Drupal user) and started reading about static functions, wherein Garfield describes both their drawbacks (really hard to test and to safely change code that uses them, as it forms tight coupling) and when to use them (when operating in the context of a type). His code had something that I hadn't seen (or noticed):

class ProductNotFound extends \InvalidArgumentException
    public readonly int $productId;
    public readonly array $query;
    public static function forId(int $id): self
        $new = new self();
        $new->productId = $id;
        $message = 'Product %d not found.';
        $new->message = sprintf($message, $id);
        return $new;
   ... // more code follows, but removed for brevity

I didn't know what the "self" type hint was, so I looked it up.

First, I found this article about the various return types in PHP, but it didn't really answer my question. Instead, I found this other post about self and parent, which cleared things up. The example of when to use a function as the "forId" example above with the "self" return is for a setter. Though the code above returns an object of the type "ProductNotFound", so it's not a setter. More like a factory? Maybe?

More things I don't understand:

  • value object (as in "ProductNotFound is an exception, and therefore a value object.")
  • dechex(int)
  • self()
  • autoloading
  • dynamic properties, though these have been deprecated in PHP 8.2, so it's not urgent to figure them out.
  • read only classes (What is a good use for this? I did make a pull request in this section, though.)
    • A little more reading, such as on, and I now understand that readonly classes are syntactic sugar for having a class with properties that are readonly.
    • And the JetBrains video on the page is helpful in describing when read only properties are useful, especially when you need to structure data, as in a data transfer object (DTO) or a value object. I feel like the DTO makes sense. You read in some other data and map it to the properties of an object. Because the properties are readonly and can only be set once, they can be public without fear that they will be overwritten or corrupted.
    • Read only properties were introduced with PHP 8.1. Because of the scenario of a DTO, you'd need to add "public readonly" to all the properties. Now, with readonly classes in 8.2, you need only write "public readonly" on the class itself, which makes all the properties readonly.
    • So what good were dynamic properties pre-8.2?