{"id":107860,"date":"2021-01-13T14:05:22","date_gmt":"2021-01-13T13:05:22","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=phpstorm&#038;p=107860"},"modified":"2021-01-22T00:34:04","modified_gmt":"2021-01-21T23:34:04","slug":"php-annotated-january-2021","status":"publish","type":"phpstorm","link":"https:\/\/blog.jetbrains.com\/zh-hans\/phpstorm\/2021\/01\/php-annotated-january-2021","title":{"rendered":"PHP Annotated \u2013 January 2021"},"content":{"rendered":"<p><a href=\"https:\/\/blog.jetbrains.com\/zh-hans\/phpstorm\/2021\/01\/php-annotated-january-2021\"><img decoding=\"async\" class=\"alignnone size-full\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/01\/phpstorm-PHP_Annotated_blog_1600x800.png\" alt=\"PHP Annotated Monthly\" \/><\/a><\/p>\n<p>Greetings everyone,<br \/>\n<\/p>\n<p>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\u2019ve got a load of articles, tools, videos, and streams, carefully selected for you.<\/p>\n<p><!--more--><\/p>\n<style>\n    .post img.alignico {\n        margin-right: 10px;\n        margin-top: 2px;\n        float: left;\n    }\n<\/style>\n<h3>&#x26a1;&#xfe0f; News<\/h3>\n<ul>\n<li>\n        <a href=\"https:\/\/www.php.net\/ChangeLog-8.php#8.0.1\" target=\"_blank\" rel=\"noopener\"><strong>PHP 8.0.1<\/strong><\/a><strong>, <\/strong><a href=\"https:\/\/www.php.net\/ChangeLog-7.php#7.4.14\" target=\"_blank\" rel=\"noopener\"><strong>7.4.14<\/strong><\/a><strong>, <\/strong><a href=\"https:\/\/www.php.net\/ChangeLog-7.php#7.3.26\" target=\"_blank\" rel=\"noopener\"><strong>7.3.26<\/strong><\/a> \u2014 All the releases have a fix for the <a href=\"https:\/\/security.archlinux.org\/CVE-2020-7071\" target=\"_blank\" rel=\"noopener\">CVE-2020-7071<\/a> 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 <a href=\"https:\/\/php.watch\/articles\/php-7.3-security-fixes-only\" target=\"_blank\" rel=\"noopener\">security-fixes-only<\/a> mode.\n    <\/li>\n<li>\n        All the PHP documentation has been <a href=\"https:\/\/externals.io\/message\/112662\" target=\"_blank\" rel=\"noopener\">moved to Git<\/a>: <a href=\"https:\/\/github.com\/php\/doc-base\" target=\"_blank\" rel=\"noopener\"><strong>github.com\/php\/doc-base<\/strong><\/a>!\n    <\/li>\n<li>\n        <a href=\"https:\/\/blog.jetbrains.com\/zh-hans\/phpstorm\/2020\/12\/phpstorm-2020-3-release\"><strong>PhpStorm 2020.3<\/strong><\/a> \u2014 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.\n    <\/li>\n<li><a href=\"https:\/\/blog.packagist.com\/php-versions-stats-2020-2-edition\/\" target=\"_blank\" rel=\"noopener\"><strong>PHP Versions Stats \u2013 2020.2<\/strong> <\/a>\u2014 he traditional compilation of statistics based on the data Composer sends when it connects to packagist.org.<br \/>\n        \u2022 <font color=\"#006400\">PHP 7.4<\/font>: 42.61% (+22.55)<br \/>\n        \u2022 <font color=\"#ff8c00\">PHP 7.3<\/font>: 27.05% (-3.00)<br \/>\n        \u2022 <font color=\"red\">PHP 7.2<\/font>: 15.28% (-12.21)<br \/>\n        \u2022 <font color=\"red\">PHP 7.1<\/font>: 7.45% (-4.1)<br \/>\n        \u2022 <font color=\"red\">PHP 5.6<\/font>: 2.71% (-2.28)<br \/>\n        \u2022 <font color=\"red\">PHP 7.0<\/font>: 2.70% (-1.30)\n    <\/li>\n<li><a href=\"https:\/\/thephp.cc\/dates\/2021\/01\/the-online-php-conference\" target=\"_blank\" rel=\"noopener\"><strong>The Online PHP Conference 2021<\/strong><\/a>, January 18\u201322 \u2014 Check out the lineup! You can still get a ticket. <\/li>\n<\/ul>\n<h3>&#x1f418; PHP Internals<\/h3>\n<ul>\n<li>&#x2705; <a href=\"https:\/\/wiki.php.net\/rfc\/restrict_globals_usage\" target=\"_blank\" rel=\"noopener\"><strong>[RFC] Restrict $GLOBALS usage<\/strong><\/a> \u2014 Accepted unanimously. Using <code>$GLOBALS<\/code> will be restricted starting from PHP 8.1. It will be possible to read, write, and call isset or unset:\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">$GLOBALS[&#039;x&#039;] = 1;\r\n\r\necho $GLOBALS[&#039;x&#039;]\r\n\r\nisset($GLOBALS[&#039;x&#039;]);\r\nunset($GLOBALS[&#039;x&#039;]);<\/pre>\n<p>But an attempt to change the variable <code>$GLOBALS<\/code> itself will cause an error:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">$GLOBALS = [];\r\n$GLOBALS =&amp; $x;\r\n$x =&amp; $GLOBALS;\r\nunset($GLOBALS);<\/pre>\n<p> An error will occur if you try to pass <code>$GLOBALS<\/code> to a function by reference:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">\r\nasort($GLOBALS);\r\n\/\/ &gt; Compile-time error<\/pre>\n<p> The implementation of this RFC simplifies the internals of PHP and improves the performance of array operations.<\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/enumerations\" target=\"_blank\" rel=\"noopener\"><strong>[RFC] Enumerations<\/strong><\/a> \u2014 Ilija Tovilo and Larry Garfield conducted <a href=\"https:\/\/github.com\/Crell\/enum-comparison\" target=\"_blank\" rel=\"noopener\">research on how enum is implemented in other languages<\/a> and presented an RFC that is inspired by Swift, Rust, and Kotlin.\n<p>Enum is essentially a type that\u2019s declared with the keywords <code>enum<\/code> and <code>case<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">enum Suit {\r\n  case Hearts;\r\n  case Diamonds;\r\n  case Clubs;\r\n  case Spades;\r\n}<\/pre>\n<p>You can assign one of the values to a variable or pass it as an argument:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">$val = Suit::Diamonds;\r\n\r\nfunction pick_a_card(Suit $suit) { ... }\r\n\r\npick_a_card($val);        \/\/ OK\r\npick_a_card(Suit::Clubs); \/\/ OK\r\npick_a_card(&#039;Spades&#039;);    \/\/ TypeError<\/pre>\n<p>Enums behave like singleton objects:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">$a = Suit::Spades;\r\n$b = Suit::Spades;\r\n\r\n$a === $b; \/\/ true\r\n\r\n$a instanceof Suit;         \/\/ true\r\n$a instanceof Suit::Spades; \/\/ true<\/pre>\n<p>It is possible to declare scalar Enums. They can be used transparently in a context where scalar values are expected:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">enum Suit: string {\r\n  case Hearts = &#039;H&#039;;\r\n  case Diamonds = &#039;D&#039;;\r\n  case Clubs = &#039;C&#039;;\r\n  case Spades = &#039;S&#039;;\r\n}&lt;br\/&gt;\r\n\r\necho &quot;I hope I draw a &quot; . Suit::Spades;\r\n\/\/ prints &quot;I hope I draw a S&quot;.<\/pre>\n<p>Enum can have methods, including static ones, as well as properties and constants.<\/p>\n<details>\n<summary>Here is an example of using a method to output a list of checkbox options:<\/summary>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">enum UserStatus: string {\r\n  case Pending = &#039;pending&#039;;\r\n  case Active = &#039;active&#039;;\r\n  case Suspended = &#039;suspended&#039;;\r\n  case CanceledByUser = &#039;canceled&#039;;\r\n\r\n  public function label(): string {\r\n    return match($this) {\r\n      UserStatus::Pending =&gt; &#039;Pending&#039;,\r\n      UserStatus::Active =&gt; &#039;Active&#039;,\r\n      UserStatus::Suspended =&gt; &#039;Suspended&#039;,\r\n      UserStatus::CanceledByUser =&gt; &#039;Canceled by user&#039;,\r\n    };\r\n  }\r\n}\r\n\r\nforeach (UserStatus::cases() as $key =&gt; $val) {\r\n  printf(&#039;&lt;option value=&quot;%s&quot;&gt;%s&lt;\/option&gt;\\n&#039;, $key, $val-&gt;label());\r\n}<\/pre>\n<\/details>\n<p>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 <code>name<\/code> and <code>value<\/code> though.<\/p>\n<p>Enums can be serialized too: <\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">\r\nSuit::Hearts === unserialize(serialize(Suit::Hearts));\r\n<\/pre>\n<p> These are just the highlights; read the <a href=\"https:\/\/wiki.php.net\/rfc\/enumerations\" target=\"_blank\" rel=\"noopener\">full RFC<\/a> to learn more.\n<\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/fibers\" target=\"_blank\" rel=\"noopener\"><strong>[RFC] Fibers<\/strong><\/a> \u2014 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 <a href=\"https:\/\/github.com\/reactphp\/reactphp\" target=\"_blank\" rel=\"noopener\">ReactPHP<\/a> \/ <a href=\"https:\/\/github.com\/amphp\/amp\" target=\"_blank\" rel=\"noopener\">Amp<\/a> in a much simpler and clearer way.\n<p><a class=\"embedly-card\" href=\"https:\/\/www.reddit.com\/r\/PHP\/comments\/kf0rgz\/php_rfc_fibers\/gg5uts6\" target=\"_blank\" rel=\"noopener\">Reddit quote<\/a><\/p>\n<blockquote class=\"twitter-tweet\">\n<p lang=\"en\" dir=\"ltr\">ReactPHP is absolutely not obsoleted by ext-fiber. Fibers<br \/>\n    will give people more of a reason to use ReactPHP, since it will be easier to integrate into existing, synchronous code. I&#39;m looking forward to async PHP becoming common instead of obscure.<\/p>\n<p>&mdash; Aaron Piotrowski (@_trowski) <a href=\"https:\/\/twitter.com\/_trowski\/status\/1342596738553671685?ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">December 25, 2020<\/a><\/p><\/blockquote>\n<p>><\/p>\n<p><a href=\"https:\/\/github.com\/amphp\/amp\/tree\/v3\" target=\"_blank\" rel=\"noopener\">Amp v3<\/a> is still under development, but it already uses fibers instead of promises. Here is <a href=\"https:\/\/github.com\/amphp\/amp\/blob\/v3\/examples\/fibers\/simultaneous-async.php\" target=\"_blank\" rel=\"noopener\">an example<\/a> of how the async\/await analog might look: <\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">\r\nuse Amp\\Delayed;\r\nuse Amp\\Loop;\r\nuse function Amp\\async;\r\nuse function Amp\\await;\r\n\r\n\/\/ Note that the closure declares int as a return type, not Promise or Generator, but executes like a coroutine.\r\n$callback = function (int $id): int {\r\n    return await(new Delayed(1000, $id)); \/\/ Await promise resolution.\r\n};\r\n\r\n\/\/ Invoking $callback returns an int, but is executed asynchronously.\r\n$result = $callback(1); \/\/ Call a subroutine within this green thread, taking 1 second to return.\r\n\\var_dump($result);\r\n\r\n\/\/ Simultaneously runs two new green threads, await their resolution in this green thread.\r\n$result = await([  \/\/ Executed simultaneously, only 1 second will elapse during this await.\r\n    async($callback, 2),\r\n    async($callback, 3),\r\n]);\r\n\\var_dump($result); \/\/ Executed in 2 seconds after the start of the entire script.<\/pre>\n<\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/deprecated_attribute\" target=\"_blank\" rel=\"noopener\"><strong>[RFC] #[Deprecated] Attribute<\/strong><\/a> \u2014 PHP 8 added support for attributes, but without any attributes out of the box. The first official proposed attribute is <code>#[Deprecated]<\/code> to mark obsolete methods and functions. If you call a function or method that is marked with <code>#[Deprecated]<\/code>, then PHP will throw an <code>E_DEPRECATED<\/code> error.\n<p>        A similar but slightly more advanced attribute is already <a href=\"https:\/\/blog.jetbrains.com\/zh-hans\/phpstorm\/2020\/12\/phpstorm-2020-3-release#deprecated\">in PhpStorm 2020.3<\/a>. However, because the native attribute <a href=\"https:\/\/github.com\/php\/php-src\/pull\/6521#pullrequestreview-558933516\" target=\"_blank\" rel=\"noopener\">is declared as final<\/a>, we are considering dropping PhpStorm&#8217;s one unless we find a good way to make them compatible.<\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/named_parameter_alias_attribute\" target=\"_blank\" rel=\"noopener\"><strong>[RFC] #[NamedParameterAlias] Attribute<\/strong><\/a> \u2014 Another attribute idea for PHP 8.1.\n<p>  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.<\/p>\n<p>There was even a separate RFC on this topic: <a href=\"https:\/\/wiki.php.net\/rfc\/renamed_parameters\" target=\"_blank\" rel=\"noopener\">Named Parameters explicit opt-in<\/a>.<\/p>\n<p>Now there\u2019s a somewhat simpler solution: add an attribute to the parameters to specify an alias, that is, an alternative name for the parameter. <\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">&lt;?php\r\n\r\nuse NamedParameterAlias;\r\n\r\n\/\/ Old function signature:\r\nfunction log($arg1) {}\r\n\r\n\/\/ New function signature introduces better name\r\nfunction log(#[NamedParameterAlias(&quot;arg1&quot;)] $message) {}\r\n\r\nlog(arg1: &quot;Hello World!&quot;);\r\nlog(message: &quot;Hello World!&quot;);\r\n<\/pre>\n<\/li>\n<li><a href=\"https:\/\/github.com\/php\/php-src\/pull\/6538\" target=\"_blank\" rel=\"noopener\"><strong>[PR] Add support for property initialization during cloning<\/a><\/strong> \u2014 This pull request presents a syntax improvement for cloning immutable objects.<br \/>\n<table>\n<tr>\n<td>Current:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">...\r\n    {\r\n        $self = clone $this;\r\n        $self-&gt;bar = $bar;\r\n        $self-&gt;baz = $baz;&lt;br\/&gt;\r\n\r\n        return $self;\r\n    }\r\n...\r\n<\/pre>\n<\/td>\n<td>Proposed:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">...\r\n    {\r\n        return clone $this with {\r\n            bar: $bar,\r\n            baz: $baz,\r\n        };\r\n    }\r\n...\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/is_list\" target=\"_blank\" rel=\"noopener\">[RFC] Add array_is_list(array $array): bool<\/a> \u2014 Voting has started on adding a function that will return <code>true<\/code> if you pass an array with consecutive integer keys to it: <code>0, 1, 2 ... count($value)-1<\/code>.<\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/short-match\" target=\"_blank\" rel=\"noopener\">[RFC] Short match<\/a><\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/improve_mysqli\" target=\"_blank\" rel=\"noopener\">[RFC] Concepts to improve mysqli extension<\/a><\/li>\n<li><a href=\"https:\/\/wiki.php.net\/rfc\/array_unpacking_string_keys\" target=\"_blank\" rel=\"noopener\">[RFC] Array unpacking with string keys<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/php\/php-src\/pull\/6583\" target=\"_blank\" rel=\"noopener\">[PR] Use &#8216;ENT_QUOTES|ENT_SUBSTITUTE&#8217; for HTML encoding and decoding functions<\/a><\/li>\n<li>PHP 8.1 received super fast hashing algorithms: <a href=\"https:\/\/php.watch\/versions\/8.1\/xxHash\" target=\"_blank\" rel=\"noopener\">xxHash<\/a> and <a href=\"https:\/\/php.watch\/versions\/8.1\/MurmurHash3\" target=\"_blank\" rel=\"noopener\">MurmurHash3<\/a>.<\/li>\n<\/ul>\n<p><\/p>\n<h3>&#128736; Tools<\/h3>\n<ul>\n<li>&#x1F4B5; <a href=\"https:\/\/freek.dev\/1868-introducing-ray-a-debugging-tool-for-pragmatic-developers\" target=\"_blank\" rel=\"noopener\">Dump Debugging Evolved &#8211; Ray<\/a> \u2014 Folks from Spatie presented their debugging app \u2014 <a href=\"https:\/\/myray.app\/\" target=\"_blank\" rel=\"noopener\">Ray<\/a>. You add <code>ray($anything)<\/code> 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.<br \/>\nSee the &#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=8F2SrxB4O2E\" target=\"_blank\" rel=\"noopener\">video overview<\/a> for more details.<\/li>\n<li><a href=\"https:\/\/github.com\/vimeo\/php-mysql-engine\" target=\"_blank\" rel=\"noopener\">vimeo\/php-mysql-engine<\/a> \u2014 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 <a href=\"https:\/\/github.com\/vimeo\/php-mysql-engine#caveat-emptor\" target=\"_blank\" rel=\"noopener\">limitations<\/a> though.<\/li>\n<li><a href=\"https:\/\/github.com\/mbunge\/php-attributes\" target=\"_blank\" rel=\"noopener\">mbunge\/php-attributes<\/a> \u2014 Package for automatic resolve\/initialization of PHP 8 attributes. You can simply plug in the autoloader or use the resolver manually.<\/li>\n<li><a href=\"https:\/\/github.com\/mlocati\/docker-php-extension-installer\" target=\"_blank\" rel=\"noopener\">mlocati\/docker-php-extension-installer<\/a> \u2014 This tool makes it easy to install PHP extensions in Docker. It is useful for PHP 8 as PECL is no longer available.<\/li>\n<li><a href=\"https:\/\/github.com\/php-opencv\/php-opencv\" target=\"_blank\" rel=\"noopener\">php-opencv\/php-opencv<\/a> \u2014 An extension for computer vision (face and object recognition, etc.) and machine learning, with PHP 8 support. See the <a href=\"https:\/\/github.com\/php-opencv\/php-opencv-examples\" target=\"_blank\" rel=\"noopener\">examples<\/a>.<\/li>\n<p><\/p>\n<li><a href=\"https:\/\/github.com\/pestphp\/pest\" target=\"_blank\" rel=\"noopener\">pestphp\/pest v1.0<\/a> \u2014 The first stable release of the testing tool, which allows you to write tests in a simpler way.<\/li>\n<li><a href=\"https:\/\/getrector.org\/blog\/2020\/12\/28\/rector-09-released\" target=\"_blank\" rel=\"noopener\">Rector 0.9<\/a> \u2014 A tool for automatic refactoring and code updates.<\/li>\n<li><a href=\"https:\/\/github.com\/FriendsOfPHP\/proxy-manager-lts\" target=\"_blank\" rel=\"noopener\">FriendsOfPHP\/proxy-manager-lts<\/a> \u2014 A fork of a popular <a href=\"https:\/\/github.com\/Ocramius\/ProxyManage.r\/\" target=\"_blank\" rel=\"noopener\">Ocramius\/ProxyManager<\/a> package with extended backward compatibility.<\/li>\n<li><a href=\"https:\/\/github.com\/multiavatar\/multiavatar-php\" target=\"_blank\" rel=\"noopener\">multiavatar\/multiavatar-php<\/a> \u2014 This script generates funny avatars based on users name (any string). Here is for <a href=\"https:\/\/multiavatar.com\/PhpStorm\" target=\"_blank\" rel=\"noopener\">&#8216;PhpStorm&#8217;<\/a>: <br \/> <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/01\/Multiavatar-PhpStorm.png\" width=\"100\"\/><\/li>\n<\/ul>\n<p><\/p>\n<h3><img decoding=\"async\" class=\"alignico\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/10\/symfony.png\" alt=\"\" width=\"16\" \/> Symfony<\/h3>\n<ul>\n<li><a href=\"https:\/\/tomasvotruba.com\/blog\/2020\/12\/21\/5-new-combos-opened-by-symfony-52-and-php-80\/\" target=\"_blank\" rel=\"noopener\">5 New Combos opened by Symfony 5.2 and PHP 8.0<\/a><\/li>\n<li><a href=\"https:\/\/macrini.medium.com\/how-to-create-service-bundles-for-a-symfony-application-f266ecf01fca\" target=\"_blank\" rel=\"noopener\">How to create service bundles for a Symfony application<\/a><\/li>\n<li><a href=\"https:\/\/symfony.com\/blog\/a-week-of-symfony-732-4-10-january-2021\" target=\"_blank\" rel=\"noopener\">A week of Symfony #732 (January 4\u201310, 2021)<\/a><\/li>\n<li><a href=\"https:\/\/symfony.com\/blog\/symfony-2020-year-in-review\" target=\"_blank\" rel=\"noopener\">Symfony 2020 in review<\/a><\/li>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=J46I-cctz7M\" target=\"_blank\" rel=\"noopener\">Consume a 3rd-party API with Test Driven Development + HttpClient<\/a><\/li>\n<p><\/p>\n<\/ul>\n<p><\/p>\n<h3><img decoding=\"async\" class=\"alignico\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/10\/laravel_36.png\" alt=\"\" width=\"16\" \/> Laravel<\/h3>\n<ul>\n<li>&#x1F508; Taylor Otwell&#8217;s <a href=\"https:\/\/blog.laravel.com\/laravel-snippet-26\" target=\"_blank\" rel=\"noopener\">Laravel Snippet #26<\/a> podcast: Jetstream 2.x, Forge Circles, Spark &#8220;Next&#8221;, React SPAs.<\/li>\n<li><a href=\"https:\/\/jasonmccreary.me\/articles\/laravel-testing-configuration-precedence\/\" target=\"_blank\" rel=\"noopener\">Configuration precedence when testing Laravel<\/a><\/li>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=cDwL_SPepeE\" target=\"_blank\" rel=\"noopener\">A stream from Freek Murzee, where he refactors one of his applications<\/a> \u2013 <a href=\"https:\/\/mailcoach.app\/\" target=\"_blank\" rel=\"noopener\">Mailcoach<\/a>.<\/li>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=zAnyX1oqEr8\" target=\"_blank\" rel=\"noopener\">Laravel Internals #3<\/a> \u2014 A stream with the entire Laravel team.<\/li>\n<\/ul>\n<p><\/p>\n<h3><img decoding=\"async\" class=\"alignico\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2020\/10\/yii.png\" width=\"16\" \/> Yii<\/h3>\n<ul>\n<li><a href=\"https:\/\/opencollective.com\/yiisoft\/updates\/yii-news-2020-issue-8\" target=\"_blank\" rel=\"noopener\">Yii news 2020, issue 8<\/a><\/li>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=eQdDBhQpU9o&#038;list=PLLQuc_7jk__UvpbpU3no5zveJQAwID48B\" target=\"_blank\" rel=\"noopener\">E-commerce website on Yii 2 <\/a> \u2014 A 16-hours long let&#8217;s play video. And here is the result: <a href=\"https:\/\/github.com\/thecodeholic\/yii2-ecommerce-website\" target=\"_blank\" rel=\"noopener\">thecodeholic\/yii2-ecommerce-website<\/a>.<\/li>\n<\/ul>\n<p><\/p>\n<h3><img decoding=\"async\" class=\"alignico\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/01\/laminas.png\" width=\"16\" \/> Laminas<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.zend.com\/blog\/laminas-2020\" target=\"_blank\" rel=\"noopener\">Laminas Project: A Year in Review<\/a>.<\/li>\n<li><a href=\"https:\/\/www.bleepingcomputer.com\/news\/security\/zend-framework-disputes-rce-vulnerability-issues-patch\/\" target=\"_blank\" rel=\"noopener\">Vulnerability reported in Zend Framework \/ Laminas<\/a> \u2014 The essence of &quot;vulnerability&quot; can be understood from this example:\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-linenumbers=\"false\" data-enlighter-title=\"\">class MyClassWithToString {\r\n    public $name;\r\n\r\n    public function __construct($name) {\r\n        $this-&gt;name = $name;\r\n    }\r\n\r\n    public function __toString() {\r\n        return (string) $this-&gt;name;\r\n    }\r\n}\r\n\r\n$input = unserialize(&#039;O:19:&quot;MyClassWithToString&quot;:1:{s:4:&quot;name&quot;;s:15:&quot;\/tmp\/etc\/passwd&quot;;}&#039;);\r\nif ($input instanceof MyClassWithToString) {\r\n    unlink($input);\r\n}<\/pre>\n<p>The team pushed <a href=\"https:\/\/github.com\/laminas\/laminas-http\/pull\/48\" target=\"_blank\" rel=\"noopener\">a fix<\/a> 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 <code>unserializie()<\/code> in such cases.<\/p>\n<p>What\u2019s more, <a href=\"https:\/\/externals.io\/message\/100147\" target=\"_blank\" rel=\"noopener\">after 2017<\/a> deserialization bugs are no longer considered security issues, simply because <code>unserialize()<\/code> will never be secure.<\/p>\n<blockquote class=\"twitter-tweet\">\n<p lang=\"en\" dir=\"ltr\">PSA: Don&#39;t use unserialize() on untrusted input (see <a href=\"https:\/\/t.co\/8GZb1xqE1u\" target=\"_blank\">https:\/\/t.co\/8GZb1xqE1u<\/a>)<br \/>PHP will no longer treat unserialize() bugs are security bugs.<\/p>\n<p>&mdash; Nikita Popov (@nikita_ppv) <a href=\"https:\/\/twitter.com\/nikita_ppv\/status\/895571304325062656?ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">August 10, 2017<\/a><\/p><\/blockquote>\n<p>Here is another <a href=\"https:\/\/blog.redteam-pentesting.de\/2021\/deserialization-gadget-chain\/\" target=\"_blank\" rel=\"noopener\">post about exploitation of such bugs<\/a> using Yii as an example.<\/li>\n<\/ul>\n<p><\/p>\n<h3>&#x1f4a1; Misc<\/h3>\n<ul>\n<li><a href=\"https:\/\/blog.wyrihaximus.net\/2021\/01\/scaling-php-fpm-based-on-utilization-demand-on-kubernetes\/\" target=\"_blank\" rel=\"noopener\">Scaling PHP FPM based on utilization demand on Kubernetes<\/a>.<\/li>\n<li><a href=\"https:\/\/peakd.com\/hive-168588\/@crell\/object-properties-and-immutability\" target=\"_blank\" rel=\"noopener\">Object properties and immutability<\/a> \u2014 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.\n<p>In the <a href=\"https:\/\/peakd.com\/hive-168588\/@crell\/object-properties-part-2-examples\" target=\"_blank\" rel=\"noopener\">second part<\/a> Larry reviews all the ideas from the first post using the PSR-7 as an example.\n    <\/li>\n<li>A fundamental post on <a href=\"https:\/\/thephp.website\/en\/issue\/bitwise-php\/\" target=\"_blank\" rel=\"noopener\">mastering binary and bitwise data in PHP<\/a>.<\/li>\n<li><a href=\"https:\/\/calendar.perfplanet.com\/2020\/profiling-php-in-production-at-scale\/\" target=\"_blank\" rel=\"noopener\">Profiling PHP in production at scale<\/a> \u2014 A post from Timo Tijhof, the principal engineer at Wikipedia. It talks about how they use their two tools: <a href=\"https:\/\/github.com\/wikimedia\/php-excimer\/\" target=\"_blank\" rel=\"noopener\">wikimedia\/php-excimer<\/a> \u2013 a sampling profiler and <a href=\"https:\/\/github.com\/wikimedia\/arc-lamp\/\" target=\"_blank\" rel=\"noopener\">wikimedia\/arc-lamp<\/a> \u2013 trace collector and flame graphs generator.<br \/>\n<blockquote><p>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.<\/p><\/blockquote>\n<\/li>\n<li><a href=\"https:\/\/medium.com\/vimeo-engineering-blog\/its-not-legacy-code-it-s-php-1f0ee0462580\" target=\"_blank\" rel=\"noopener\">It\u2019s not legacy code \u2014 it\u2019s PHP<\/a> \u2014 An inspiring post by Matt Brown, author of Psalm, on how and why they use PHP at Vimeo.<\/li>\n<\/ul>\n<h3>&#x1F4FA; Videos<\/h3>\n<ul>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=xHbP3bshU3U\" target=\"_blank\" rel=\"noopener\">A pragmatic introduction to Event Sourcing<\/a> from Frank de Jonge, the author of <a href=\"https:\/\/github.com\/EventSaucePHP\/EventSauce\" target=\"_blank\" rel=\"noopener\">EventSaucePHP\/EventSauce<\/a>.<\/li>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=GqUvoK7PfOA\" target=\"_blank\" rel=\"noopener\">A video code-review from Matthieu Napoli<\/a> \u2014 In this episode, he looks closely at <a href=\"https:\/\/github.com\/m50\/simple\" target=\"_blank\" rel=\"noopener\">m50\/simple<\/a>.<\/li>\n<li>&#x1F4FA; <a href=\"https:\/\/www.youtube.com\/watch?v=HF61HJHEYMk\" target=\"_blank\" rel=\"noopener\">Xdebug 3 modes<\/a> \u2014 A video from Derick Rethans, the author of Xdebug, about configuring Xdebug as a debugger\/profiler\/coverage collector.<\/li>\n<\/ul>\n<h3>&#x1F64C; Community<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.php-fig.org\/blog\/2020\/12\/announcing-new-discord-server\/\" target=\"_blank\" rel=\"noopener\">PHP-FIG now has a Discord server<\/a><\/li>\n<li><a href=\"https:\/\/cults3d.com\/en\/3d-model\/various\/elephpant-3d\" target=\"_blank\" rel=\"noopener\">A 3D model of elePHPant<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/thank-you-php\/thank-you-php\" target=\"_blank\" rel=\"noopener\">github.com\/thank-you-php<\/a> \u2014 An open letter of gratitude to PHP. You can sign up just by sending a pull-request and get a <img decoding=\"async\" src=\"https:\/\/avatars0.githubusercontent.com\/u\/34204326?s=60&#038;v=4\" width=\"30\"\/> badge to your profile.<\/li>\n<li><a href=\"https:\/\/inphpinity.elephpant.com\/\" target=\"_blank\" rel=\"noopener\">elephpant PHP8 : InPHPinity is born<\/a> \u2014 A new PHP 8 elephant is available for pre-order:<br \/>\n        <img decoding=\"async\" src=\"https:\/\/www.exakat.io\/wp-content\/uploads\/2020\/12\/inphpinity-1024x538.jpeg\" width=\"300\"><\/li>\n<\/ul>\n<hr>\n<p>Thanks for reading!<\/p>\n<p>If you have any interesting or useful links to share via PHP Annotated, please leave a comment on this post or send me a <a href=\"https:\/\/twitter.com\/pronskiy\" target=\"_blank\" rel=\"noopener\">tweet<\/a>.<\/p>\n<p style=\"text-align: left;\" align=\"center\"><a class=\"jb-download-button\" title=\"Complete this form and get PHP Annotated Monthly delivered fresh to your email\" href=\"https:\/\/info.jetbrains.com\/PHP-Annotated-Subscription.html\" target=\"_blank\" rel=\"noopener\">Subscribe to PHP Annotated<\/a><\/p>\n<p><em>Your JetBrains PhpStorm team<\/em><br \/>\n<em>The Drive to Develop<\/em><\/p>\n<p><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><br \/>\n<script async src=\"https:\/\/embed.redditmedia.com\/widgets\/platform.js\" charset=\"UTF-8\"><\/script><\/p>\n","protected":false},"author":869,"featured_media":21799,"comment_status":"closed","ping_status":"closed","template":"","categories":[],"tags":[2633,2213,190,6433,2323,2648,191,1116,2632],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/phpstorm\/107860"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/phpstorm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/types\/phpstorm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/users\/869"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/comments?post=107860"}],"version-history":[{"count":10,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/phpstorm\/107860\/revisions"}],"predecessor-version":[{"id":108905,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/phpstorm\/107860\/revisions\/108905"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media\/21799"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/media?parent=107860"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/categories?post=107860"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/tags?post=107860"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/zh-hans\/wp-json\/wp\/v2\/cross-post-tag?post=107860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}