PHP 8.1.0 RC 1 available for testing – PHP: Hypertext Preprocessor

The PHP team is pleased to announce the release of PHP 8.1.0, RC 1. This is the first release candidate, continuing the PHP 8.1 release cycle, the rough outline of which is specified in the PHP Wiki. For source downloads of PHP 8.1.0, RC 1 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 16 September 2021. The signatures for the release can be found in the manifest or on the QA site. Thank you for helping us make PHP better.

Advanced PHPUnit shenanigans – Larry Garfield

Advanced PHPUnit shenanigans

In my last post, we talked about PHPUnit’s data providers, and how to leverage them to write more maintainable tests. Today, I want to talk about two more test-writing techniques that I’ve found to be very helpful.

Continue reading this post on PeakD.

Larry
1 September 2021 – 11:27am

Quick Testing Tips: Self-Contained Tests – Matthias Noback

Whenever I read a test method I want to understand it without having to jump around in the test class (or worse, in dependencies). If I want to know more, I should be able to “click” on one of the method calls and find out more.

I’ll explain later why I want this, but first I’ll show you how to get to this point.

As an example, here is a test I encountered recently:

public function testGetUsernameById(): void
{ $userRepository = $this->createUserRepository(); $username = $userRepository->getUsernameById(1); self::assertSame('alice', $username);
}

The way I read this:

/* * Ah, we're testing the UserRepository, so we instantiate it. * The factory method probably injects a connection to the test * database or something: */
$userRepository = $this->createUserRepository(); /* * Now we fetch a username by its ID. The ID is 1. That's the * first time I see it in this test. This probably means that * there is no user with this ID and the method will throw * an exception or return a default name or something: */
$username = $userRepository->getUsernameById(1); /* * Wait, the username is supposed to be "alice"? * Where did that come from? */
self::assertSame('alice', $username);

So while trying to understand this test that last line surprised me. Where does Alice come from?

As it turns out there is a setupTables() function which is called during the setup phase. This method populates the database with some user data that is used in various ways by one of the test methods in the class.

private function setupTables(): void
{ $this->connection->table('users') ->insert( [ ['user_id' => 1, 'username' => 'alice', 'password' => 'alicepassword'], ['user_id' => 2, 'username' => 'bob', 'password' => 'bobpassword'], ['user_id' => 3, 'username' => 'john', 'password' => 'johnpassword'], ['user_id' => 4, 'username' => 'peter', 'password' => 'peterpassword'], ] ); // ...
}

There are some problems with this approach:

  • It’s not clear which tests rely on which database records (a common issue with shared database fixtures). So it’s hard to change or remove tests, or the test data, when needed. As an example, if we remove one test, maybe some test data could also be removed but we don’t really know. If we change some test data, one of the tests may break.
  • It’s not clear which of the values is actually relevant. For example, we’re interested in user 1, 'alice', but is the password relevant? Most likely not.

The first thing we need to do is ensure that each test only creates the database records that it really needs, e.g.

public function testGetUsernameById(): void
{ $this->connection->table('users') ->insert( [ 'user_id' => 1, 'username' => 'alice', 'password' => 'alicepassword' ] ); $userRepository = $this->createUserRepository(); $username = $userRepository->getUsernameById(1); self::assertSame('alice', $username);
}

At this point the test is already much easier to understand on its own. You can clearly see where the number 1 and the string 'alice' come from. There’s only that 'alicepassword' string that is irrelevant for this test. Leaving it out gives us an SQL constraint error. But we can still get rid of it here by extracting a method for creating a user record, moving the insert() out of sight:

public function testGetUsernameById(): void
{ $this->createUser(1, 'alice'); $userRepository = $this->createUserRepository(); $username = $userRepository->getUsernameById(1); self::assertSame('alice', $username);
} private function createUser(int $id, string $username): void
{ $this->connection->table('users') ->insert( [ 'user_id' => $id, 'username' => $username, 'password' => 'a-password' ] );
}

Going back to the beginning of this post:

  • When I read a test method I want to understand it without having to jump around in the test class (or worse, in dependencies).
  • If I want to know more, I should be able to “click” on one of the method calls and find out more.

With just a few simple refactoring steps we’ve been able to achieve these things. As a consequence we achieve th

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

PHP Internals News: Episode 94: Unwrap Reference After Foreach – Derick Rethans

PHP Internals News: Episode 94: Unwrap Reference After Foreach

In this episode of “PHP Internals News” I chat with Nikita Popov (Twitter, GitHub, Website) about the “First Class Callable Syntax” RFC.

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode’s MP3 file, and it’s available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news

Transcript

Derick Rethans 0:14

Hi, I’m Derick. Welcome to PHP internals news, the podcast dedicated to explaining the latest developments in the PHP language. This is Episode 94. Today I’m talking with Nikita Popov about the unwrap reference after foreach RFC that he’s proposing. Nikita, would you please introduce yourself?

Nikita Popov 0:33

Hi, Derick. I’m Nikita and I work at JetBrains on PHP core development.

Derick Rethans 0:38

So no changes compared to the last time.

Nikita Popov 0:41

Yes, at the time before that.

Derick Rethans 0:43

So what is the problem that is RFC is going to solve?

Nikita Popov 0:46

Well, it’s really a very minor thing. I think it’s a relatively well known problem for the more experienced PHP programmers. It’s like a classic example, you have a foreach loop by reference. So foreach array as value by reference, and then you do a second loop after that, foreach array as value at the same it’s by value. So without the reference sign. The result of that is that your last two array elements are going to be the same, which is kind of unexpected. If you’re not familiar with how references in PHP work and scoping in PHP works. So I think it’s worth explaining what’s going on there.

Derick Rethans 1:27

Can you quickly explain the scoping or rather the lack of it, I suppose?

Nikita Popov 1:31

Yeah, it’s really the lack of PHP really only has function scoping. So if you have a foreach array as value, then the value variable is going to stay alive, even after the foreach loop. And usually, that won’t make much of a difference. So you will just have like reference to the last element of the array, might even be useful for some cases, you know, before we added the array, I think, array_key_last function. If the last element now is a reference, so if you have a reference to the last element, then you’re write into that variable is also going to modify the last element of the array. So if you now have a second foreach loop, using the same variable, that’s actually not just modifying that variable, but it’s also always modifying the last element of the array.

Derick Rethans 2:15

Okay, just to clarify, it isn’t necessarily the last element in the foreach loop. It’s the last one that’s been assigned to?

Nikita Popov 2:22

Yeah, that’s, that’s true.

Derick Rethans 2:24

Is this not something that people actually use for some useful reasons?

Nikita Popov 2:28

As mentioned before, technically, you could use it to get a reference to the last element and then modify the last element outside the foreach loop. I don’t think this is a particularly common use case. But I’m sure people have used in here there. This is a use case we would break with the proposed RFC.

Derick Rethans 2:47

I think it is one I have used in the past,

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

Fun with PHPUnit Data Providers – Larry Garfield

Fun with PHPUnit Data Providers

Most PHP developers are familiar with PHPUnit these days. It is the most widely used testing framework for PHP by a wide margin (although others do exist). One of its more under-utilized features, though is data providers.

Data providers are a PHPUnit feature (and many testing frameworks have an equivalent) that lets you run a single test method multiple times but with different data. Often it’s presented as a way to save typing, but I find it is also a useful architectural tool, too. And there are ways to use them that are even nicer than what most people tend to do.

Continue reading this post on PeakD.

Larry
24 August 2021 – 12:13pm

On using PSR abstractions – Matthias Noback

Several years ago, when the PHP-FIG (PHP Framework Interop Group) created its first PSRs (PHP Standard Recommendations) they started some big changes in the PHP ecosystem. The standard for class auto-loading was created to go hand-in-hand with the then new package manager Composer. PSRs for coding standards were defined, which I’m sure helped a lot of teams to leave coding standard discussions behind. The old tabs versus spaces debate was forever settled and the jokes about it now feel quite outdated.

Next up were the PSRs that aimed for the big goal: framework interoperability. It started with an easy one: PSR-3 for logging, but it took quite some time before the bigger ones were tackled, e.g. request/response interfaces, HTTP client and server middleware interfaces, service container interfaces, and several others. The idea, if I remember correctly, was that frameworks could provide implementation packages for the proposed interfaces. So you could eventually use the Symfony router, the Zend container, a Laravel security component, and so on.

I remember there were some troubles though. Some PSRs were abandoned, some may not have been developed to their full potential, and some may have been over-developed. I think it’s really hard to find common ground between framework implementations for all these abstractions, and to define abstractions in such a way that users and implementers can both be happy (see for example an interesting discussion by Anthony Ferrara about the HTTP middleware proposal and an older discussion about caching).

One of the concerns I personally had about PSR abstractions is that once you have a good abstraction, you don’t need multiple implementation packages. So why even bother creating a separate abstraction for others to use? Why not just create a single package that has both the implementation and the abstraction? It turns out, that doesn’t work. Why? Because package maintainers sometimes just abandon a package. And if that happens, the abstraction becomes useless too because it is inside that abandoned package. So developers do like to have a separate abstraction package that isn’t even tied to their favorite vendor.

(By the way, I think it’s strange for frameworks to have their own Interfaces or Contracts package for their abstractions. I bet there are 0 cases where someone using Laravel or Symfony keeps using its abstractions, but not its implementations. Anyway… If you have a different experience, or want to share your story about these packages, please submit a comment below!)

Is it safe to depend on PSR abstraction packages?

Back in 2013, Igor Wiedler made a lasting impression with their article about dependency responsibility. By now we all know that by installing a vendor package you can import bugs and security issues into your project. Another common concern is the stability of the package: is it going to be maintained for a long time? Are the maintainers going to change it often?

Yes, these concerns should be addressed, and I think in general they are not considered well enough. But we need to distinguish between different kinds of packages. Packages have a certain level of stability which is in part related to its abstractness and the number of dependencies it has (if you’re interested in this topic, check out my book “Principles of Package Design”).

The abstractness of a package is based on the number of interfaces versus the number of classes. Since abstract things are supposed to change less often than concrete things, and in fewer ways, an abstract package will be a stable package and it will be more reliable than less abstract, i.e. concrete packages (I think this is why frameworks provide those Interface or Contract packages: as an indication of their intended stability).

Another reason for a package to become stable is when it is used by many people. This is more of a social principle: the maintainers won’t change the package in drastic ways if that makes the users of the package angry. Of course, we have semantic versioning and backward compatibility promises for th

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

PHP Internals News: Episode 93: Never For Parameter Types – Derick Rethans

PHP Internals News: Episode 93: Never For Parameter Types

In this episode of “PHP Internals News” I chat with Jordan LeDoux (GitHub) about the “Never For Parameter Types” RFC.

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode’s MP3 file, and it’s available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news

Transcript

Derick Rethans 0:14

Hi, I’m Derick. Welcome to PHP internals news, a podcast dedicated to explaining the latest developments in the PHP language. This is Episode 93. It’s been quiet over the last month, so it didn’t really have a chance to talk about upcoming RFCs mostly because there were none. However, PHP eight one’s feature freeze has happened now, a new RFCs are being targeted for the next version of PHP eight two. Today I’m talking with Jordan LeDoux, about the Never For Parameter Types RFC, the first one targeting this upcoming PHP version. Jordan, would you please introduce yourself?

Jordan LeDoux 0:50

Certainly. And thanks for having me. My name is Jordan. I’ve worked as a developer for about 15 years now. Most of my career has been spent working in PHP. Although professionally, I’ve had experience working in C#, Python, TypeScript, mostly in the form of JavaScript, but a little bit of Node and, you know, a variety of other languages that I haven’t spent enough time in to really be proficient in any real way. But recently, I decided to do something that I have thought about doing for many years, but never actually jumped into which is exploring the PHP engine itself and how I could possibly contribute to it.

Derick Rethans 1:32

And here we are, but your first our thing.

Jordan LeDoux 1:35

Yeah, it’s exciting.

Derick Rethans 1:36

What is this RFC about, what does it propose?

Jordan LeDoux 1:39

Well, this RFC proposes allowing the never type, which was added in 8.1 as a return value, to parameters for functions and methods on objects. The main idea behind that is that when never was proposed as a return type, it was meant to signal that the function would never return. Not that it returns void, which of course, void signifies which is returning no value or returning, returning without any specified information. And never return signifies that the function will never return, which is a concept that exists in many other languages. And for that purpose in other languages, what’s usually used is something called a bottom type. And that’s what never ended up being. And I’m proposing that we extend the use of that bottom type to other areas where the type may be helpful.

Derick Rethans 2:38

So a bottom type, that might be a new term for many people, it will certainly for me when I looked at the never RFC for as return types. Can you sort of explain what a bottom type is, especially thinking about object oriented theory with something that we’d like to call the Liskov Substitution Principle? And also, how does it apply to argument types?

Jordan LeDoux 2:59

Let’s start with the Liskov Substitution. The general idea behind Liskov Substitution is that if A is a subtype of B, then anywhere that A exists, you should be able to substitute B. It has to do with when you have a class hierarchy in in an object oriented language, that that class hierarchy guarantees certain things about substitutionality, like whether or not something can be substituted for something else. That affects language design in ways that a lot of programmers are kind of intuitively familiar with, but maybe not familiar with the theory and the ideas behind it more concretely. But LSP is the principl

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

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

The PHP team is pleased to announce the release of PHP 8.1.0, Beta 3. This is the third beta release, continuing the PHP 8.1 release cycle, the rough outline of which is specified in the PHP Wiki. For source downloads of PHP 8.1.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 2 September 2021. The signatures for the release can be found in the manifest or on the QA site. Thank you for helping us make PHP better.

Changelog generator for GitHub milestones – Rob Allen

For many years now, I’ve been using Matthew Weier O’Phinney’s changelog_generator script to generate an easy-to-read list of changes for a given milestone. Time has moved on; the Laminas project now uses Laminas Automatic Releases and Matthew hasn’t updated his script since 2013. Since PHP 8, warnings have started appear, so it’s clear updates were required. While I fully intend to see if I can use Automatic Releases on some projects, I have others where this is unlikely to happen and will continue to use changelog-generator.

Looking into it, I worked out that the warnings were from dependent packages. PHP has changed a bit since 2013. My first idea was to simply update to the latest Laminas versions of the dependencies, but I discovered that the Console and Http components are no longer actively maintained, so new components would be needed. I don’t particuarly want to have to do this all again in a few years time when the replacements that I pick don’t support PHP 8.4 or whatever, so I decided to remove the dependencies completely.

Looking at Console, I quickly realised that only one class was used by changelog-generator: Getopt, which worked fine under PHP 8. So, I copied that one class to src, changed the namespace and called it done. For Http, I wrote a new HttpClient class that only makes GET requests using PHP’s curl functions. I’m reasonably confident that the API to those functions won’t be changing signicantly.

While I was messing around, I also fixed a few bugs so that searching by title will look for closed milestones and it now lists the last 20 milestones if you don’t provide an argument. Just a couple of quality of life features to make make it easier for me to use.

My version is now up on Packagist if you need something like this. However, I strongly recommend looking at Laminas Automatic Releases as that automates all the work required for doing a release. If you just need a formatted list of closed issues though, grab this and see if it works for you.

Thoughts on dependencies

My general view is that if it’s not core to your application, then using a dependent package is the way forward. There’s rarely any benefit from spending time working on something that others have already built and to which you are not adding value. This is particularly true for applications where you are adding new features and have better things to do.

However, sometimes this isn’t the right choice. In this case, I need a very small subset of what a dependent package provides. I took the view that maintaining the dependencies would be more long-term work than writing the small components that I actually needed. Particularly, as this tool is stable.

Sometimes this is the right choice for a component in my big projects too.