Categories


Archives


Recent Posts


Categories


Commerce Bug and PHP 8.1/Magento 2.4.4

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

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

  1. 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

  2. I spent my usual 20 minutes staring at a new Apache FastCGI configuration before spotting my incorrect redundancy in the paths

  3. 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 port 9200 it was looking for.

  4. 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.

Copyright © Alan Storm 1975 – 2022 All Rights Reserved

Originally Posted: 27th May 2022