PHP Annotated – January 2021

PHP Annotated Monthly

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 and case:

    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 and value 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.

    Reddit quote

    >

    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 an E_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

Laravel

Yii

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.

    Here is another post about exploitation of such bugs using Yii as an example.

💡 Misc

📺 Videos

🙌 Community


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.

Subscribe to PHP Annotated

Your JetBrains PhpStorm team
The Drive to Develop


image description