Category Archives: Allgemein

Attributes are awesome

Especially in combination with constructor property promotion.

Recently I did a code-review on an entity from a PHP8.0 project. What I saw was this:

The origin

<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'user')]
class User
{
    #[ORM\Id]
    #[ORM\Column(type: 'integer', unique: true)]
    public int $id;

    #[ORM\Column(type: 'string')]
    public string $username;

    #[ORM\Column(type: 'string')]
    public string $passwordhash;

    public function __construct(
        int $id,
        string $username,
        string $passwordhash,
    ) {
        $this->id = $id;
        $this->username = $username;
        $this->passwordhash = $passwordhash;
    }
}

I was thinking about using constructor property promotion to get rid of the property declaration and property assignment but immediately thought that that would require us to handle the attributes differently. So I shortly checked my favourite search engine and realized that indeed we are able to shorten this whole stuff considerably:

The result

<?php


declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'user')]
class User
{
    public function __construct(
        #[ORM\Id]
        #[ORM\Column(type: 'integer', unique: true)]
        public int $id,
        #[ORM\Column(type: 'string')]
        public string $username,
        #[ORM\Column(type: 'string')]
        public string $passwordhash,
    ) {}
}

Combining the attributes with the constructor property promotion allows much smaller entity definitions.

Immutability

In our case we also cleared a misunderstanding. My colleague was under the impression that Doctrine requires properties to be public. Otherwise they are not able to be hydrated properly. That is not the case and Doctrine can perfectly hydrate private properties!

So we decided to go for private properties in combination with getters. As in our concrete implementation we actually also need to execute some logic before returning some of the values. So declaring the properties private and having getters provides us with a truly immutable entity.

As we are not using PHP8.1 yet we could not make use of the new readonly declaration which would have solved the issue with the immutability though as we need logic in some cases the approach with using getters always makes more sense in this particular setup.

Enums. With PHP < 8.1

Recently I had to build something where an Enum would have been perfect.

But…

The Challenge

It needed to run on PHP 8.0. Of course.

So what to do? I decided to build an Enum like thingy that I can easily upgrade into a real Enum once we are on PHP8.1 with that project.

Why not use a library for that? There are plenty of libraries on packagist that already provide you with the basics!

For one thing: I only needed one Enum. Not a multitude. And Adding a further dependency to make creating one enum easier that will (hopefully) converted into a “eral” enum in about half a year? That sounds bit like taking the sledgehammer to crack a nut.

And on the other hand it turned out that creating an enum from scratch isn’t rocket science.

Continue reading Enums. With PHP < 8.1

On deprecating dynamic properties

Yesterday the RFC regarding Deprecating Dynamic Properties went into voting phase and it currently looks like the overwhelming majority supports the RFC.

But nevertheless the discussions yesterday started in the wider PHP community whether that is a good idea or not.

To summarize the RFC in very short terms: Currently PHP allows to assign values to a class property that was not previously declared. The RFC proposes to remove this implicit feature in PHP9. It will still be available as an explicit feature when the creator of the class adds an Annotation [AllowDynamicProperties] on the class level.

To prepare for that, in the next minor version of PHP – PHP 8.2 – whenever one assigns a value to an undeclared property there will be a deprecation notice raised.

So the proposal is – in essence – about moving from implicitness to explicitness. Which is in my opinion a very good move.

So what is the discussion that I was talking about previously all about? After all that sounds like a good move, doesn’t it?

Continue reading On deprecating dynamic properties

Farewell Enigmail

Thunderbird has End-to-End encryption right built into it’s very core. But at a price that was annoying to me. So I decided to keep the old 68 Version together with the enigmail plugin.

Until my system recently did an update and replaced the old thunderbird with the shiny new version 78. Which comes with its very own implementation of Pretty Good Privacy – better known as PGP.

Short recap: The Enigmail plugin used a system-installed GnuPG installation (Open Source PGP-Implementation). Thunderbird on the other hand uses a library called RNP.

This has 2 drawbacks. One is, that it is a bit harder to setup my current workflow which uses a private key located on a Yubikey that I have to unlock. The setup was not as easy as it was described in some of the descriptions on the internet. But that was mainly due to my own fault. A configuration setting that did work with Enigmail but didn’t with the new Version of Thunderbird.

The main issue is that RNP currently does not support hardware tokens. But luckily there is a flag that can delegate tasks that require private keys to a third party app. So I could setup the default GnuPG to handle the signing and the decryption process. One additional advantage is that I do not need to expose private keys to Thunderbird where they need to be secured by a single master password. But that is a different story.

RNP is not GnuPG

The – for me – more annoying part is, that RNP does not use the systemwide GnuPG keychain but its own one. So for me that means that I have to maintain two keychains with public keys.

I found that a bit awkward. So I looked for a way to automatically keep the two keychains in sync. And after a bit of digging I figured, that Thunderbird keeps a GnuPG compatible public keychain right in Thunderbirds profile folder. So all I have to do is write a cron-job that exports all the public keys from one keychain and moves them over to the respective other one. Already existing keys will not be imported, missing ones will be imported though.

So this is what I now have installed as cron-job:

#!/bin/bash
  
THUNDERBIRD_PROFILE=~/.thunderbird/<profile-folder>
gpg --no-default-keyring \
    --keyring=$THUNDERBIRD_PROFILE/pubring.gpg \
    --export \
    --armor | gpg --import --no
gpg --export --armor | gpg \
    --no-default-keyring \
    --keyring=$THUNDERBIRD_PROFILE/pubring.gpg \
    --import \
    --no

Optimization will follow soon by replacing the hard-coded path to the profile folder with a command that reads that from thunderbirds profile.ini file. But that is a different story.

The only drawback I have seen so far is that Thunderbird needs to be restarted after the script has actually imported one or more keys into the thunderbilrd keychain. Otherwise the new keys are not recognized.

But that is much less of a hassle and drawback than not being able to sign my outgoing email or decrypt my incoming mails.