PHP Annotated – January 2021
Greetings everyone,
In this edition of PHP Annotated, read about the top PHP news from the year so far. These include PHP 8.0.1 and other releases, fibers for async PHP, Enums, first native attributes, and other proposals for PHP 8.1. And as usual, we’ve got a load of articles, tools, videos, and streams, carefully selected for you.
⚡️ News
- PHP 8.0.1, 7.4.14, 7.3.26 — All the releases have a fix for the CVE-2020-7071 vulnerability in the url_parse() function. 8.0 and 7.4 have also received lots of other fixes, and PHP 7.3 is now in security-fixes-only mode.
- All the PHP documentation has been moved to Git: github.com/php/doc-base!
- PhpStorm 2020.3 — In case you missed it, the new release of PhpStorm comes with support for PHP 8, PHPStan and Psalm, Xdebug 3, Tailwind CSS, and pair programming.
- PHP Versions Stats – 2020.2 — he traditional compilation of statistics based on the data Composer sends when it connects to packagist.org.
• PHP 7.4: 42.61% (+22.55)
• PHP 7.3: 27.05% (-3.00)
• PHP 7.2: 15.28% (-12.21)
• PHP 7.1: 7.45% (-4.1)
• PHP 5.6: 2.71% (-2.28)
• PHP 7.0: 2.70% (-1.30) - The Online PHP Conference 2021, January 18–22 — Check out the lineup! You can still get a ticket.
🐘 PHP Internals
- ✅ [RFC] Restrict $GLOBALS usage — Accepted unanimously. Using
$GLOBALS
will be restricted starting from PHP 8.1. It will be possible to read, write, and call isset or unset:$GLOBALS['x'] = 1; echo $GLOBALS['x'] isset($GLOBALS['x']); unset($GLOBALS['x']);
But an attempt to change the variable
$GLOBALS
itself will cause an error:$GLOBALS = []; $GLOBALS =& $x; $x =& $GLOBALS; unset($GLOBALS);
An error will occur if you try to pass
$GLOBALS
to a function by reference:asort($GLOBALS); // > Compile-time error
The implementation of this RFC simplifies the internals of PHP and improves the performance of array operations.
- [RFC] Enumerations — Ilija Tovilo and Larry Garfield conducted research on how enum is implemented in other languages and presented an RFC that is inspired by Swift, Rust, and Kotlin.
Enum is essentially a type that’s declared with the keywords
enum
andcase
:enum Suit { case Hearts; case Diamonds; case Clubs; case Spades; }
You can assign one of the values to a variable or pass it as an argument:
$val = Suit::Diamonds; function pick_a_card(Suit $suit) { ... } pick_a_card($val); // OK pick_a_card(Suit::Clubs); // OK pick_a_card('Spades'); // TypeError
Enums behave like singleton objects:
$a = Suit::Spades; $b = Suit::Spades; $a === $b; // true $a instanceof Suit; // true $a instanceof Suit::Spades; // true
It is possible to declare scalar Enums. They can be used transparently in a context where scalar values are expected:
enum Suit: string { case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S'; }<br/> echo "I hope I draw a " . Suit::Spades; // prints "I hope I draw a S".
Enum can have methods, including static ones, as well as properties and constants.
Here is an example of using a method to output a list of checkbox options:
enum UserStatus: string { case Pending = 'pending'; case Active = 'active'; case Suspended = 'suspended'; case CanceledByUser = 'canceled'; public function label(): string { return match($this) { UserStatus::Pending => 'Pending', UserStatus::Active => 'Active', UserStatus::Suspended => 'Suspended', UserStatus::CanceledByUser => 'Canceled by user', }; } } foreach (UserStatus::cases() as $key => $val) { printf('<option value="%s">%s</option>\n', $key, $val->label()); }
You can call Enum methods on specific cases, but cases cannot have their own methods or constants. Cases are just values, but they do have special properties like
name
andvalue
though.Enums can be serialized too:
Suit::Hearts === unserialize(serialize(Suit::Hearts));
These are just the highlights; read the full RFC to learn more.
- [RFC] Fibers — A huge proposal on asynchronous PHP. Basically, fibers are functions that have their own stack and therefore can be stopped and resumed anytime. That will allow us to write asynchronous code based on libraries like ReactPHP / Amp in a much simpler and clearer way.
ReactPHP is absolutely not obsoleted by ext-fiber. Fibers
will give people more of a reason to use ReactPHP, since it will be easier to integrate into existing, synchronous code. I'm looking forward to async PHP becoming common instead of obscure.— Aaron Piotrowski (@_trowski) December 25, 2020
>
Amp v3 is still under development, but it already uses fibers instead of promises. Here is an example of how the async/await analog might look:
use Amp\Delayed; use Amp\Loop; use function Amp\async; use function Amp\await; // Note that the closure declares int as a return type, not Promise or Generator, but executes like a coroutine. $callback = function (int $id): int { return await(new Delayed(1000, $id)); // Await promise resolution. }; // Invoking $callback returns an int, but is executed asynchronously. $result = $callback(1); // Call a subroutine within this green thread, taking 1 second to return. \var_dump($result); // Simultaneously runs two new green threads, await their resolution in this green thread. $result = await([ // Executed simultaneously, only 1 second will elapse during this await. async($callback, 2), async($callback, 3), ]); \var_dump($result); // Executed in 2 seconds after the start of the entire script.
- [RFC] #[Deprecated] Attribute — PHP 8 added support for attributes, but without any attributes out of the box. The first official proposed attribute is
#[Deprecated]
to mark obsolete methods and functions. If you call a function or method that is marked with#[Deprecated]
, then PHP will throw anE_DEPRECATED
error.A similar but slightly more advanced attribute is already in PhpStorm 2020.3. However, because the native attribute is declared as final, we are considering dropping PhpStorm’s one unless we find a good way to make them compatible.
- [RFC] #[NamedParameterAlias] Attribute — Another attribute idea for PHP 8.1.
During the discussion and voting for named arguments, there was one very controversial point: the backward compatibility issues of renaming. OSS maintainers pointed out that parameter names would now become part of the API and could not be easily changed.
There was even a separate RFC on this topic: Named Parameters explicit opt-in.
Now there’s a somewhat simpler solution: add an attribute to the parameters to specify an alias, that is, an alternative name for the parameter.
<?php use NamedParameterAlias; // Old function signature: function log($arg1) {} // New function signature introduces better name function log(#[NamedParameterAlias("arg1")] $message) {} log(arg1: "Hello World!"); log(message: "Hello World!");
- [PR] Add support for property initialization during cloning — This pull request presents a syntax improvement for cloning immutable objects.
Current: ... { $self = clone $this; $self->bar = $bar; $self->baz = $baz;<br/> return $self; } ...
Proposed: ... { return clone $this with { bar: $bar, baz: $baz, }; } ...
- [RFC] Add array_is_list(array $array): bool — Voting has started on adding a function that will return
true
if you pass an array with consecutive integer keys to it:0, 1, 2 ... count($value)-1
. - [RFC] Short match
- [RFC] Concepts to improve mysqli extension
- [RFC] Array unpacking with string keys
- [PR] Use ‘ENT_QUOTES|ENT_SUBSTITUTE’ for HTML encoding and decoding functions
- PHP 8.1 received super fast hashing algorithms: xxHash and MurmurHash3.
🛠 Tools
- 💵 Dump Debugging Evolved – Ray — Folks from Spatie presented their debugging app — Ray. You add
ray($anything)
calls in your code, and when you run a PHP script, the data is displayed nicely in a separate desktop application. Give it a try if you prefer the dump-and-die approach over Xdebug.
See the 📺 video overview for more details. - vimeo/php-mysql-engine — MySQL engine in pure PHP can come in handy when you access the database when testing and want to speed up the launch of tests by emulating MySQL in memory. The library extends the PDO class and allows you to call regular PDO methods of MySQL. Note the limitations though.
- mbunge/php-attributes — Package for automatic resolve/initialization of PHP 8 attributes. You can simply plug in the autoloader or use the resolver manually.
- mlocati/docker-php-extension-installer — This tool makes it easy to install PHP extensions in Docker. It is useful for PHP 8 as PECL is no longer available.
- php-opencv/php-opencv — An extension for computer vision (face and object recognition, etc.) and machine learning, with PHP 8 support. See the examples.
- pestphp/pest v1.0 — The first stable release of the testing tool, which allows you to write tests in a simpler way.
- Rector 0.9 — A tool for automatic refactoring and code updates.
- FriendsOfPHP/proxy-manager-lts — A fork of a popular Ocramius/ProxyManager package with extended backward compatibility.
- multiavatar/multiavatar-php — This script generates funny avatars based on users name (any string). Here is for ‘PhpStorm’:
Symfony
- 5 New Combos opened by Symfony 5.2 and PHP 8.0
- How to create service bundles for a Symfony application
- A week of Symfony #732 (January 4–10, 2021)
- Symfony 2020 in review
- 📺 Consume a 3rd-party API with Test Driven Development + HttpClient
Laravel
- 🔈 Taylor Otwell’s Laravel Snippet #26 podcast: Jetstream 2.x, Forge Circles, Spark “Next”, React SPAs.
- Configuration precedence when testing Laravel
- 📺 A stream from Freek Murzee, where he refactors one of his applications – Mailcoach.
- 📺 Laravel Internals #3 — A stream with the entire Laravel team.
Yii
- Yii news 2020, issue 8
- 📺 E-commerce website on Yii 2 — A 16-hours long let’s play video. And here is the result: thecodeholic/yii2-ecommerce-website.
Laminas
- Laminas Project: A Year in Review.
- Vulnerability reported in Zend Framework / Laminas — The essence of "vulnerability" can be understood from this example:
class MyClassWithToString { public $name; public function __construct($name) { $this->name = $name; } public function __toString() { return (string) $this->name; } } $input = unserialize('O:19:"MyClassWithToString":1:{s:4:"name";s:15:"/tmp/etc/passwd";}'); if ($input instanceof MyClassWithToString) { unlink($input); }
The team pushed a fix to the framework. But if you look more closely, the vulnerability relates to the deserialization of data from a user. And it says in red on php.net that you should not use
unserializie()
in such cases.What’s more, after 2017 deserialization bugs are no longer considered security issues, simply because
unserialize()
will never be secure.PSA: Don't use unserialize() on untrusted input (see https://t.co/8GZb1xqE1u)
PHP will no longer treat unserialize() bugs are security bugs.— Nikita Popov (@nikita_ppv) August 10, 2017
Here is another post about exploitation of such bugs using Yii as an example.
💡 Misc
- Scaling PHP FPM based on utilization demand on Kubernetes.
- Object properties and immutability — A detailed analysis by Larry Garfield of how write restrictions can be implemented in PHP. As a conclusion, he proposes adding separate modifiers for read and write access, i.e. separate public/private for get and set and clone-with functionality.
In the second part Larry reviews all the ideas from the first post using the PSR-7 as an example.
- A fundamental post on mastering binary and bitwise data in PHP.
- Profiling PHP in production at scale — A post from Timo Tijhof, the principal engineer at Wikipedia. It talks about how they use their two tools: wikimedia/php-excimer – a sampling profiler and wikimedia/arc-lamp – trace collector and flame graphs generator.
We ingest about 3 million samples daily from a cluster of 150 Apache servers in any given data centre, using a 60s sample interval. These are all received by a single Redis instance.
- It’s not legacy code — it’s PHP — An inspiring post by Matt Brown, author of Psalm, on how and why they use PHP at Vimeo.
📺 Videos
- 📺 A pragmatic introduction to Event Sourcing from Frank de Jonge, the author of EventSaucePHP/EventSauce.
- 📺 A video code-review from Matthieu Napoli — In this episode, he looks closely at m50/simple.
- 📺 Xdebug 3 modes — A video from Derick Rethans, the author of Xdebug, about configuring Xdebug as a debugger/profiler/coverage collector.
🙌 Community
- PHP-FIG now has a Discord server
- A 3D model of elePHPant.
- github.com/thank-you-php — An open letter of gratitude to PHP. You can sign up just by sending a pull-request and get a badge to your profile.
- elephpant PHP8 : InPHPinity is born — A new PHP 8 elephant is available for pre-order:
Thanks for reading!
If you have any interesting or useful links to share via PHP Annotated, please leave a comment on this post or send me a tweet.
Your JetBrains PhpStorm team
The Drive to Develop