Is it a DTO or a Value Object? – Matthias Noback

A common misunderstanding in my workshops (well, whose fault is it then? ;)), is about the distinction between a DTO and a value object. And so I’ve been looking for a way to categorize these objects without mistake.

What’s a DTO and how do you recognize it?

A DTO is an object that holds primitive data (strings, booleans, floats, nulls, arrays of these things). It defines the schema of this data by explicitly declaring the names of the fields and their types. It can only guarantee that all the data is there, simply by relying on the strictness of the programming language: if a constructor has a required parameter of type string, you have to pass a string, or you can’t even instantiate the object. However, a DTO does not provide any guarantee that the values actually make sense from a business perspective. Strings could be empty, integers could be negative, etc.

There are different flavours of the class design for DTOs:

/** * @object-type DTO * * Using a constructor and public readonly properties: */
final class AnExample
{ public function __construct( public readonly string $field, // ... ) { }
} /** * @object-type DTO * * Using a constructor with private readonly properties * and public getters: */
final class AnotherExample
{ public function __construct( private readonly string $field, // ... ) { } public function field(): string { return $this->field; }
}

Regarding the naming of a DTO: I recommend not adding “DTO” to the name itself. If you want to make it clear what the type is, add a comment, or an invented annotation (or attribute) like @object-type. This will be very useful for developers that are not aware of these object types. It may trigger them to look up an article about what it means (this article, maybe :)).

What’s a value object and how do you recognize it?

A value object is an object that wraps one or more values or value objects. It guarantees that all the data is there, and also that the values make sense from a domain perspective. Strings will no longer be empty, numbers will be verified to be in the correct range. A value object can offer these guarantees by throwing exceptions inside the constructor, which is private, forcing the client to use one of the static, named constructors. This makes a value object easy to recognize, and clearly distinguishable from a DTO:

final class AnExample
{ private function __construct( private string $value ) { } public static function fromValue( string $value ): self { /* * Throw an exception when the value doesn't * match all the expectations. */ return new self($value); }
}

While a DTO just holds some data for you and provides a clear schema for this data, a value object also holds some data, but offers evidence that the data matches the expectations. When the value object’s class is used as a parameter, property, or return type, you know that you are dealing with a correct value.

How should we use these object types?

Meaning is defined by use. If we are using “DTO” and “value object” in the wrong way, their names will eventually get a different meaning. This might be how the confusion between the two terms arises in the first place.

DTOs

A DTO should only be used in two places: where data enters the application or where it leaves the application. Some examples:

  1. When a controller receives an HTTP POST request, the request data may have any shape. We need to go from shapeless data to data with a schema (verified keys and types). We can use a DTO for this. A form library may be able to populate this DTO based on submitted form data, or we can use a serializer to convert the plain-text request body to a populated DTO.
  2. When we make an HTTP POST request to a web service, we may collect the input data in a DTO first, and then serialize it to a request body that our HTTP client can send to the service.
  3. For queries the situation is similar. Here we can use a DTO to represent the query result. As an example we can pass a DTO to a template to render a view based on it. We can use a DTO, serialize it to JSON and send it back as an API response.
  4. When we send an HTTP GET request to a web service, we may deserialize the API response into a DTO first, so we can apply a known schema to it instead of just accessing array keys and guessing the types. API client packages usually offer DTOs for requests and responses.

Truncated by Planet PHP, read more at the original (another 1622 bytes)

A step-debugger for the PHP AST – Matthias Noback

When you’re learning to write custom rules for PHPStan or Rector, you’ll have to learn more about the PHP programming language as well. To be more precise, about the way the interpreter parses PHP code. The result of parsing PHP code is a tree of nodes which represents the structure of the code, e.g. you’ll have a Class definition node, a Method definition node, and within those method Statement nodes, and so on. Each node can be checked for errors (with PHPStan), or automatically refactored in some way (with Rector).

The tree of nodes is called Abstract Syntax Tree, and a successful PHPStan or Rector rule starts with selecting the right nodes from the tree and “subscribing” your rule to these nodes. A common approach for this is to start var_dump-ing or echo-ing nodes inside your new rule, but I’ve found this to be quite tedious. Which is why I’ve created a simple command-line tool that lets you inspect the nodes of any given PHP file.

The tool is called AST Inspector and is available on GitHub.

Install it with Composer:

composer require --dev matthiasnoback/php-ast-inspector

Then run:

vendor/bin/ast-inspect inspect [file.php]

You’ll see something similar to this output:

Screenshot of PHP AST inspector

You can navigate through the tree by going to the next or previous node, or jumping into the subnodes of the selected node. Navigation conveniently uses the a,s,d,w keys.

Currently the project uses the PHP-Parser library for parsing. Since PHPStan adds additional virtual nodes to the AST, it will be useful to show them in this tool as well, but that requires some additional work. Another interesting addition would be to show the types that PHPStan derives for variables in the inspected code. That will also require some more work…

For now, please give this program a try, and let me know what you think! I’m happy to add more features to it, as long as it makes the learning curve for these amazing tools less steep. And if you’re looking for an in-depth exploration of writing your own PHPStan or Rector rules, check out the documentation linked above or one of my books (Recipes for Decoupling, which shows how to create PHPStan rules, and Rector – The Power of Automated Refactoring, which does the same for Rector).

Ubuntu bungled the Firefox Snap package transition – Evert Pot

I’m not a Snap hater. On paper it’s a good idea, but as a user I shouldn’t
really be aware that ‘snaps’ even exist. In Ubuntu 21.10, Firefox became
a snap package.

Arguably the browser is the most important application in an operating
system. Here’s a non-exhaustive list of issues I’ve personally ran into.
I should note that some of these issues are now fixed, but I wanted to
illustrate what Ubuntu launched with:

  • KeePassXC, an open source password managers’ browser extension no longer works.
  • Firefox thinks that when opening ‘localhost:8080’ should open the URI scheme ‘localhost’ and tries to
    find an application that supports this scheme (now fixed!)
  • Gnome shell integration extension, the primary way to install
    gnome add-ons is now broken.
  • ‘Set image as desktop background’ is broken.
  • Opening applications via a custom URI scheme no longer asks for confirmation, this makes it possible
    to (for example) launch a bittorrent client like Transmission via a magnet: uri without asking a
    user.
  • The Mozilla VPN product has a neat feature that lets
    you have specific containers always use a VPN. This doesn’t work.
  • Firefox creates a ‘firefox.tmp’ directory in the Downloads folder (fixed!)
  • When there’s an update to the Firefox package, the following notification appears, once per day.
    Restarting Firefox does not make this go away. The official answer is to run snap refresh firefox to
    make it go away.

This is just the stuff I ran into myself, (and I have reported most of these). I imagine the total list of bugs must be way higher.
I don’t usually go out and complain on the internet like this, especially when it’s about open source projects.
I’m a Linux user, so I’ve kind of come to expect things to not be quite as polished as some of its commercial
counterparts. They’re small trade-offs to support Open Source.

However, I’m so surprised by the lack of quality control for arguably the #1 application on the #1 linux distro I’m
frankly flabbergasted, and for the first time since switching from Debian to Ubuntu 15ish years ago I’m considering
jumping ship again. What happened here?

Comments? Reply to this tweet

PHP 8.2.0 RC1 available for testing – PHP: Hypertext Preprocessor

The PHP team is pleased to announce the first release candidate of PHP 8.2.0, RC 1. This continues the PHP 8.2 release cycle, the rough outline of which is specified in the PHP Wiki.For source downloads of PHP 8.2.0 RC1 please visit the download page.Please carefully test this version and report any issues found in the bug reporting system.Please DO NOT use this version in production, it is an early test version.For more information on the new features and other changes, you can read the NEWS file, or the UPGRADING file for a complete list of upgrading notes. These files can also be found in the release archive.The next release will be the second release candidate (RC 2), planned for Sept 15th 2022.The signatures for the release can be found in the manifest or on the QA site.Thank you for helping us make PHP better.

PHP 8.2.0 Beta 3 available for testing – PHP: Hypertext Preprocessor

The PHP team is pleased to announce the third beta release of PHP 8.2.0, Beta 3. This continues the PHP 8.2 release cycle, the rough outline of which is specified in the PHP Wiki.For source downloads of PHP 8.2.0 Beta 3 please visit the download page.Please carefully test this version and report any issues found in the bug reporting system.Please DO NOT use this version in production, it is an early test version.For more information on the new features and other changes, you can read the NEWS file, or the UPGRADING file for a complete list of upgrading notes. These files can also be found in the release archive.The next release will be the first release candidate (RC 1), planned for Sept 1 2022.The signatures for the release can be found in the manifest or on the QA site.Thank you for helping us make PHP better.

On syntactic sugar – Evert Pot

Ever so often the term ‘syntactic sugar’ comes when people discuss language
features, and it’s not uncommon to see the word ‘just’ right in front of it;
some examples:

The ‘just’ has a lot of meaning here. To me it suggests that language features
that are ‘just’ syntactic sugar, aren’t quite as important as features that
aren’t. Maybe it even suggests to me that the language would be fine without.

So while the above two examples both argue that both Javascript classes and
async/await aren’t syntactic sugar, they also kind of come to the defence
of those features and justify their existence. In other cases when people
call something syntactic sugar, it’s often in a context that’s somewhat
dismissal of the feature.

I think this is a bit odd and also confuses people, especially since any
actual definition I’ve found is generally positive, such as this one from
Wikipedia.

In computer science, syntactic sugar is syntax within a programming language
that is designed to make things easier to read or to express. It makes the
language “sweeter” for human use: things can be expressed more clearly, more
concisely, or in an alternative style that some may prefer.

The thing is, isn’t every language feature beyond the bare minimum of what
makes a language turing-complete syntax sugar?

  • You don’t need classes because you can use functions and structs.
  • You don’t really need types because everything can fit in a string.
  • Functions can be implemented with goto.
  • Multiply can be implemented with addition.
  • or and and, xor can be implemented with nand.
  • async/await can be implemented with generators.

These are all incredibly useful features that make it easier to read and write
code and express ideas. Almost every language feature could be considered
syntactic sugar. That’s not a bad thing, it’s just uninteresting to point out.

Simple Solutions 1 – Active Record versus Data Mapper – Matthias Noback

Having discussed different aspects of simplicity in programming solutions, let’s start with the first topic that should be scrutinized regarding their simplicity: persisting model objects. As you may know, we have competing solutions which fall into two categories: they will follow either the Active Record (AR) or the Data Mapper pattern (DM) (as described in Martin Fowler’s “Patterns of Enterprise Application Architecture”, abbrev. PoEAA).

Active record

How do we recognize the AR pattern? It’s when you instantiate a model object and then call save() on it:

$user = new User('Matthias'); $user->save();

In terms of simplicity as seen from the client’s perspective, this is amazing. We can’t imagine anything that would be easier to use. But let’s take a look behind the scenes. If we’d create our own AR implementation, then the save() function looks something like this:

final class User
{ public function __construct( private string $name ) { } public function save(): void { // get the DB connection $connection->execute( 'INSERT INTO users SET name = ?', [ $this->name ] ); }
}

In order for save() to be able to do its work, we need to somehow inject the database connection object to the save(), so it can run the necessary INSERT SQL statement. Two options:

One, we let save() fetch the connection:

use ServiceLocator\Database; final class User
{ // ... public function save(): void { $connection = Database::getConnection(); $connection->execute( 'INSERT INTO users SET name = ?', [ $this->name ] ); }
}

The practice of fetching dependencies is called service location, and it’s often frowned upon, but for now this does the trick. However, the simplicity score goes down, since we have to import the service locator, and call a method on it (-2 points?).

The second option is to pass the connection somehow to the User object. The wrong approach is this:

use ServiceLocator\Database; final class User
{ // ... public Connection $connection; public function save(): void { $this->connection->execute( // ... ); }
}

That’s because the burden of providing the Connection is now on the call site where the User is instantiated:

$user = new User();
$user->connection = /* ... get the connection */;
// ...

This would definitely cost points in the “ease-of-use” category. A better idea is to provide the connection in the framework’s bootstrap code somehow:

final class User
{ // ... public static Connection $connection; public function save(): void { self::$connection->execute( // ... ); }
} // Somewhere in the framework boot phase:
User::$connection = /* get the connection from the container */;

Because we don’t want to do this setup step for every model class, and because we are likely doing similar things in the save() function of every model, and because we want each of our model classes to have a save() function anyway, every AR implementation will end up with a more generalized, reusable approach. The way to do that is to remove the specifics (e.g. the table and column names) and define a parent class that can do everything. This parent class defines a few abstract methods so the model is forced to fill in the details:

abstract class Model
{ public static Connection $connection; abstract protected function tableName(): string; /** * @return array<string, string> */ abstract protected function dataToSave(): array; public function save(): void { $dataToSave = $this->dataToSave(); $columnsAndValues = /* turn into column = ? */; $values = /* values for parameter binding */; $this->connection->execute( 'INSERT INTO ' . $this->tableName() . ' SET ' . $columnsAndValues, $values ); }
} // Pass the connection to all models at once:
Model::$connection = /* get the connection from the container */;

We should award ourselves several simplicity points in the area of reusability! The AR model class i

Truncated by Planet PHP, read more at the original (another 7660 bytes)

Xdebug Update: July 2022 – Derick Rethans

Xdebug Update: July 2022

In this monthly update I explain what happened with Xdebug development in this past month. These are normally published on the first Tuesday on or after the 5th of each month.

Patreon and GitHub supporters will get it earlier, around the first of each month.

You can become a patron or support me through GitHub Sponsors. I am currently 46% towards my $2,500 per month goal. If you are leading a team or company, then it is also possible to support Xdebug through a subscription.

In July, I spend 18 hours on Xdebug, with 32 hours funded. I have been on holiday, so was not be able to dedicate as much time as I wanted to.

Xdebug 3.2

Most of the work that I did on Xdebug was related to release the first two alpha releases of Xdebug 3.2, which add support for PHP 8.2, and drops support for PHP 7.2, PHP 7.3, and PHP 7.4. I do not enjoy dropping support for older PHP versions, but the additional time it costs to maintain older versions, and have their configurations run on CI, is not really worth my time. Of course, users of PHP 7.2 through PHP 7.4 can continue to use Xdebug 3.1. The guidelines of which PHP versions Xdebug supports is outlined in the documentation.

Now that PHP 8.2 itself has approached beta state, it was time to release the first alphas of Xdebug 3.2 as well. In the near future, when PHP 8.2 comes into their Release Candidates cycle, I will release beta versions of Xdebug 3.2 as well, with a stable release when PHP 8.2.0 comes out.

These alphas and betas are an excellent opportunity to try out Xdebug 3.2, as well as PHP 8.2, to see whether your projects support the latest PHP version, and how Xdebug 3.2 interacts with that.

The main new features in Xdebug 3.2 can now also be tested. And these include:

  • Support for PHP 8.2.

  • The step debugger now introduces an extra step when returning from a function, so that you can inspect the return value. This is supported in the PHP Debug Adapter for Visual Studio Code, but not yet in PhpStorm, although there is a ticket.

  • You can now configure a list of headers to scan for through the xdebug.client_discovery_header setting, instead of only being able to set one. The documentation for this is yet to follow.

  • The step debugger now supports the pseudo hosts xdebug://gateway and xdebug://nameserver as values to the xdebug.client_host setting. These pseudo-hosts instruct Xdebug to try to make a debugging connection to the default gateway and name server (as configured on Linux through /etc/resolv.conf and friends) respectively. The documentation for this is yet to follow too.

I am intending to create a video for each of these new features for my YouTube channel.