Clearing warnings from PHP8.4
Moving over to PHP8.4 essentially from PHP7.3 throws up numerous problems, and while deprecated errors can be hidden, this is counter productive since we have had several points at which earlier deprecated warnings have resulted in those elements being removed already, so come up as errors. A useful source of information is php.watch which seems a lot more useful than the migration guides on php.net, but then I've not actually used THEM recently! Now that I am more in control I can follow up on that mistake and simplify these notes! One thing I do need to document is control of PHP error_reporting and I do at least seem to have that under control, but the aim is to run with E_ALL on live sites.
Below are some of the errors coming up with PHP8.4, but key elements are generic across a lot of the code base.
- Can't pass null to the '@BitBase::verifyId( $xxx )' function. The function was originally designed to silently return false when the variable one is checking has not been set, but now PHP is complaining. The fix is fairly easy by adding ?? 0 to simply force the $xxx to a default value. In addition, since the function will not produce an exception, the @ is also redundant, so the code becomes "BitBase::verifyId( $xxx ?? 0 )" but there were a lot of them.
'PHP WARNING on linux-desktop: Undefined array key "xxx"'
is mainly down to the same problem as above, where in the past a null value was silently returned when a dynamic element has not been created. It looks like in the future everything will have to be defined even if 90% of them are never used on a particular pass through the code. Adding a check for !empty($xxx) is the normal fix but again lots of places to update.
"Attempt to access property on null"
1. Nullsafe Operator (?->):
The "?->"
null safe operator lets you safely access properties or methods of potentially null variables without throwing errors. If the variable is null, the expression returns null.
<code>{{ $blog->author?->name }}
</code>
2. optional():
The optional()
helper function is available in Laravel starting from version 5.5. It allows you to gracefully access properties or methods of potentially null variables by returning either null or the value if the variable is not null.
<code>{{ optional($blog->author)->name }}
</code>
3. Null Coalescing Operator (??):
The null coalescing operator "??"
returns the left-hand side if it's not null, otherwise, it returns the right-hand side default value.
<code>{{ $blog->author->name ?? 'Unknown' }}
</code>
4. withDefault()
The withDefault()
method in Laravel's Eloquent ORM creates a related model with default values if it doesn't exist.
<code>use App\Models\Author;
class Blog extends Model {
public function author() {
return $this->belongsTo(Author::class)->withDefault([
'name' => 'Anonymous',
]);
}
}
</code>
In this example, if the blog's author is null when accessed, Laravel will automatically create a new "Author" model with the name set to 'Anonymous'.
PHP Warning Deprecated: Creation of dynamic property
The warning is telling you that there is a property you are trying to set which isn't declared in the class or any of its parents.
When you run this:
<code>class database { public $username = "root"; public $password = "pasword"; public $port = 3306; public function __construct($params = array()) { foreach ($params as $key => $value) { $this->{$key} = $value; } } } $db = new database(array( 'database' => 'db_name', 'server' => 'database.internal', ));</code>
It is roughly equivalent to this:
<code>class database { public $username = "root"; public $password = "pasword"; public $port = 3306; } $db = new database; $db->database = 'db_name'; $db->server = 'database.internal';</code>
The warning is that there is no line in the class definition saying that $db->database
or $db->server
exist.
For now, they will be dynamically created as untyped public properties, but in future, you will need to declare them explicitly:
<code>class database { public $database; public $server; public $username = "root"; public $password = "pasword"; public $port = 3306; public function __construct($params = array()) { foreach ($params as $key => $value) { $this->{$key} = $value; } } } $db = new database(array( 'database' => 'db_name', 'server' => 'database.internal', ));</code>
In some rare situations, you actually want to say "the properties of this class are whatever I decide to add at run-time"; in that case, you can use the #[AllowDynamicProperties]
attribute, like this:
<code>#[\AllowDynamicProperties] class objectWithWhateverPropertiesIWant { public function __construct($params = array()) { foreach ($params as $key => $value) { $this->{$key} = $value; } } }</code>