I recently pulled myself out of Magento retirement to give Commerce Bug a few minor adjustments that should make it Magento 2.4.4 and PHP 8.1 compatible. If you’re still seeing problems get in touch and we’ll get you sorted out.
The extension ran into a few issues with PHP 8.1’s new levels of strictness around types. For what it’s worth, while I dislike PHP’s direction w/r/t stricter typing by default they are doing this right — these changes come through as Deprecated warnings.
The problem is twofold: First — Commerce Bug is a developer’s tool, which means it’s most often used in developer mode where every error/warning/notice is turned into an uncaught exception. Second — while Magento 2.4.4 is advertised as being PHP 8.1 ready, there are a lot of defacto-standard APIs that produce Deprecation warnings.
Optional Params Must be Optional
The first problem was a bit of institutional sloppiness on my part. I had some code that looked like this
public function __construct(
Template\Context $context,
array $data = [],
ViewVars $viewVars)
The problem here was that $data
had a default value, but $viewVars
did not. PHP 8.1 flags this as a problem.
PHP Deprecated: Optional parameter $data declared before required parameter $viewVars is implicitly treated as a required parameter
Which — fair enough. PHP is saying that because there’s no way to skip the $data
parameter that it’s essentially never optional and that the default value will never be used.
This is a wart that’s all over a lot of my old code. Some PHP core functions allow you to force a default value by passing null
into a function. I’d (incorrectly) internalized that this behavior applied to userland functions as well, so I had a habit of leaving code like the above in place because I thought it improved flexibility.
It was preg_split
that taught be this bad habit.
$test = preg_split('/,/','one,two,three',null, PREG_SPLIT_OFFSET_CAPTURE);
var_dump($test);
For what it’s worth, PHP 8.1 no longer allows this.
PHP Deprecated: preg_split(): Passing null to parameter #3 ($limit) of type int is deprecated
Instead, preg_split
requires you to pass -1
to the limit if you want to get the default behavior.
Explode
The second problem was a problem with the explode
function. It also no longer accepts null
as its second paramater. The following code
$value = null;
$test = explode('.', $value);
results in
Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated
This one was less my problem and more Magento’s. For over a decade Magento’s had block objects. These objects render HTML. Some of these block objects have template files associated with them. You can get the full path to a template by calling the block’s getTemplateFile
method
$block->getTemplateFile()
Commerce Bug is a debugging extension that (among other things) lists all the blocks rendered on the page along with their full file paths. It uses this method a lot.
Sometimes, despite being a template block, a block won’t have a template set. The Magento\Customer\Block\Account\Navigation
block is one of these. Call getTemplateFile
on a block like this and you’ll get back something false-ish (perhaps false
, perhaps null
).
Unfortunately, part of the long call stack that happens under a call to getTemplateFile
includes a call to explode. This means if you call getTemplateFile
in PHP 8.1 on a block that doesn’t have a template set, you get
Exception #0 (Exception): Deprecated Functionality: explode(): Passing null to parameter #2 ($string) of type string is deprecated
So, despite being billed as PHP 8.1 ready, there are still a lot of sharp edges for Magento developers to cut themselves on. The fix, in this case, is pretty straightforward — run a quick validation on the path before passing it in to explode
public static function normalizePath($path)
{
$path = $path ? $path : '';
$parts = explode('/', $path);
However, when I think of running Magento’s open source contribution gauntlet all will leaves my body (which, one wonders, if that’s the intent of some of the folks behind the gauntlet). So it falls on the extension developer or client programmer to do something gross like this in order to work around the issue.
<?php
namespace Pulsestorm\Commercebug\Block;
use Exception;
class GetTemplateFile {
public function get($block) {
if(!$block) { return; }
$templateFile = '';
try {
$templateFile = $block->getTemplateFile();
} catch (Exception $e) {
}
return $templateFile;
}
}
So it was an OK off-hours trip of programming down memory lane.
Other things that caught me off guard
-
Magento Template Blocks are now just named Templates (although they still inherit from the
AbstractBlock
). I might have known this at one point, but you remember the metaphors you cut your teeth on -
I spent my usual 20 minutes staring at a new Apache FastCGI configuration before spotting my incorrect redundancy in the paths
-
Magento now requires a running Elasticsearch instance to get through the install and the Google-able tricks to skip this no longer work. This was complicated by the fact that the Elasticsearch homebrew package didn’t work for me — but
brew install opensearch
gave Magento’s installed the port9200
it was looking for. -
The admin is automatically set up with 2fa but email doesn’t work out of the box on a dev machine — disabling the 2fa package completely removed this barrier to login.