PHP 7.x to PHP 8.2 Migration Guide

PHP 7.x to PHP 8.2 Migration Guide

Starting with release 9.13.012, Scriptcase is compatible with PHP 8.2, both in the development environment and in production.
When migrating directly from PHP 7.x to PHP 8.2, custom code (events, methods, and internal or external libraries) may start generating warnings, deprecations, or even fail, due to behavior changes and the discontinuation of features introduced in newer PHP versions.

This tutorial brings together the main points to watch for when migrating to PHP 8.2, with explanations and practical examples to help you adapt your code and reduce the impact during the update.

1) Nested ternary operators without explicit parentheses — Not allowed

Conditional expressions using nested ternary operators without explicit parentheses are not allowed in PHP 8.2.
This type of syntax can lead to ambiguities and is no longer accepted by the PHP interpreter.

❌ Not allowed example:
  1. $result = $aa != "" ? $xxx : isset($bb) && $bb != "" ? $zzz : "";
✅ Recommended approach:
Rewrite the logic explicitly using conditional structures:
  1. if ($aa != "") {
  2.     $result = $xxx;
  3. } elseif (isset($bb) && $bb != "") {
  4.     $result = $zzz;
  5. } else {
  6.     $result = "";
  7. }

2) Accessing array and string values using curly braces — Deprecated

Accessing values from arrays and strings using the curly braces syntax {} is not allowed in PHP 8.2.
This format is deprecated and may generate warnings or runtime errors.

Always use square brackets [] to access indexes.

❌ Not allowed example:
  1. $array = [1, 2];
  2. echo $array{1};
  3. $string = "foo";
  4. echo $string{0};
Quote
This type of access generates messages such as:
Deprecated: Array and string offset access syntax with curly braces is deprecated

✅ Correct approach:
  1. $array = [1, 2];
  2. echo $array[1]; // outputs 2
  3. $string = "foo";
  4. echo $string[0]; // outputs "f"

3) Required parameters after optional parameters — Deprecated

Declaring functions or methods with required parameters after optional parameters is not allowed in PHP 8.2.
This type of signature is considered incorrect and may generate warnings or deprecations at runtime.

❌ Not allowed example:
  1. function foo($param_optional = null, $param_required) {
  2.     // ...
  3. }
Quote
This type of declaration may generate messages such as:
Deprecated: Required parameter $param_required follows optional parameter $param_optional

✅ Correct approach:
Always declare required parameters first, followed by optional parameters:
  1. function foo($param_required, $param_optional = null) {
  2.     // ...
  3. }

4) Arithmetic operations with non-numeric strings — Not allowed

Arithmetic operations involving non-numeric strings are not allowed in PHP 8.2.
This type of operation may generate warnings or errors, because values that do not represent numbers are no longer implicitly treated as zero.

❌ Not allowed example:
  1. $b = "";
  2. $a = $b + 2;
Quote
This type of operation may result in an error because $b does not contain a valid numeric value.

✅ Correct approach:
Before performing the operation, make sure the value is numeric.

Example 1 — direct validation:
  1. $a = is_numeric($b) ? $b + 2 : 2;

Example 2 — value normalization:
  1. if (!is_numeric($b)) {
  2.     $b = 0;
  3. }
  4. $a = $b + 2;

5) Non-existent variables and indexes — Watch out for warnings

Using undefined variables or non-existent array indexes may generate warnings in PHP 8.2.
This happens when the code tries to access values that have not been defined yet.

If warnings are enabled, these situations may result in frequent messages during runtime.

❌ Not recommended example:
  1. $a = $b + 2;
Or:
  1. $a = $array['key'] + 2;
Quote
When $b or $array['key'] do not exist, a warning may be displayed.

✅ Correct approach:
Before using a variable or an array index, check whether it exists.
  1. $a = isset($b) ? $b + 2 : 2;
Or, for arrays:
  1. $a = isset($array['key']) ? $array['key'] + 2 : 2;

6) `each()` function — Removed


The each() function returns the current key/value pair of an array and advances its internal pointer.

This function is not available in PHP 8.2.
If it is used in your applications, the code must be updated before deploying to an environment with PHP 8.2 or higher.

Common replacement options:
  1. foreach()
  2. key()
  3. current()
  4. next()

❌ Not supported example:
  1. $result = "";

  2. $tab = array(
  3.     0 => array('tp' => 1, 'vl' => 'aaa'),
  4.     1 => array('tp' => 2, 'vl' => 'bbb'),
  5.     2 => array('tp' => 3, 'vl' => 'ccc')
  6. );

  7. while (list($key, $val) = each($tab)) {
  8.     $result .= $tab[$key]["vl"];
  9. }

✅ Recommended approach (using foreach()):
  1. $result = "";

  2. $tab = array(
  3.     0 => array('tp' => 1, 'vl' => 'aaa'),
  4.     1 => array('tp' => 2, 'vl' => 'bbb'),
  5.     2 => array('tp' => 3, 'vl' => 'ccc')
  6. );

  7. foreach ($tab as $key => $val) {
  8.     $result .= $tab[$key]["vl"];
  9. }

7) `array_key_exists()` function — Using it on objects is deprecated

The array_key_exists() function checks whether a key or index exists in an array.
In PHP 8.2, using this function to check object properties is deprecated.

For this scenario, use isset() or property_exists().

❌ Not recommended example:
  1. if (array_key_exists('index', $array1)) {
  2.     // code
  3. }
✅ Recommended approach:
  1. if (isset($array1['index'])) {
  2.     // code
  3. }

8) `money_format()` function — Removed

The money_format() function formats a number as a currency string.

This function is not available in PHP 8.2.
To format currency values, use the Intl extension through the NumberFormatter class.

❌ Not supported example:
  1. echo money_format("%.2n", 1234.56);
✅ Recommended approach (using NumberFormatter):
  1. $currencyObject = new NumberFormatter("pt-BR", NumberFormatter::CURRENCY);
  2. echo $currencyObject->format(1234.56);

9) `mb_strrpos()` function — Encoding parameter is deprecated

The mb_strrpos() function finds the position of the last occurrence of a value in a string.

In PHP 8.2, passing the encoding as the third parameter is deprecated.
Instead, pass an offset as the third parameter and the encoding as the fourth.

❌ Not recommended example:
  1. $string = 'O rato roeu a roupa';
  2. echo mb_strrpos($string, 'roeu', 'UTF-8');
✅ Correct approach:
  1. $string = 'O rato roeu a roupa';
  2. echo mb_strrpos($string, 'roeu', 0, 'UTF-8');

10) Dynamic properties — Deprecated

In PHP 8.2, creating properties that do not exist in the class directly on an object (for example, $obj->new = 1;) triggers a deprecation notice.
This behavior is only allowed when the class explicitly permits dynamic properties or when the object is of type stdClass.

Before (no warning):
It was possible to create dynamic properties on objects without PHP emitting any warnings.
  1. class User {} $u = new User();
  2. $u->name = "Ana"; // dynamic property
PHP 8.2 (triggers deprecation):
This type of usage now triggers a deprecation notice. To avoid it, you can:
  1. Declare the property directly in the class;
  2. Use the #[\AllowDynamicProperties] attribute (temporary workaround);
  3. Use WeakMap when you do not have control over the class.

11) Relative callables — Deprecated

Some callable formats that worked with call_user_func(), but do not work correctly when executed as $callable(), have been marked as deprecated in PHP 8.2. This includes calls that depend on class context, such as "self::method", "parent::method", "static::method" and ["self", "method"].

Avoid using:
  1. call_user_func("self::doStuff");
  2. call_user_func(["self", "doStuff"]);
Use instead:
The fully qualified class name:
  1. call_user_func("MyClass::doStuff");
  2. call_user_func(["MyClass", "doStuff"]);
Or a closure, when you need access to the current context:
  1. call_user_func(fn() => $this->doStuff());

12) "${var}" and "${expr}" interpolation in strings — Deprecated

In PHP 8.2, using string interpolation in the "${var}" and "${expr}" formats has been marked as deprecated, as this style is less clear and may cause ambiguity.

Avoid:
  1. echo "Hello ${name}";
  2. echo "Total: ${arr['total']}";
Use:
  1. echo "Hello $name";
  2. echo "Hello {$name}";
  3. echo "Total: {${arr['total']}}"; // for expressions

13) utf8_encode() and utf8_decode() — Deprecated

The utf8_encode() and utf8_decode() functions have been marked as deprecated in PHP 8.2, as they assume a fixed encoding, which may lead to incorrect results in different scenarios.
Common replacements:
  1. mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1') // adjust the source encoding as needed
  2. iconv('ISO-8859-1', 'UTF-8//TRANSLIT', $str) // when applicable
Quote
These functions assume ISO-8859-1 as the default encoding, which may cause confusion and incorrect conversions; therefore, they were deprecated.

14) Case-insensitive functions and uppercase/lowercase conversion — Behavior change

In PHP 8.2, several functions that convert or compare text in a case-insensitive way now follow ASCII rules (default “C” locale). This includes functions such as strtolower(), strtoupper(), ucwords(), and str_ireplace().
With this change, these functions no longer consider language-specific rules, which may affect accented characters or languages with special capitalization rules, such as Portuguese (pt-BR) and Turkish (tr-TR).

To correctly handle localized text or accented characters, use the MBString extension, for example:
  1. mb_strtolower($text, 'UTF-8');

15) glob() with open_basedir — Return value change

In PHP 8.2, the behavior of the glob() function changed when the open_basedir directive is enabled.
  1. If all paths are blocked by open_basedir, glob() now returns an empty array ([]) — previously, it returned false.
  2. If only some paths are blocked, a warning may be displayed.
Code that may be affected:
  1. $files = glob($pattern);
  2. if ($files === false) {
  3.     // ...
  4. }

Update the check to also consider the [] return value, ensuring the code properly handles both scenarios.

Fix (handle false and []):
  1. $files = glob($pattern);
  2. if ($files === false || $files === []) {
  3.     // No files found OR access blocked by open_basedir
  4.     // handle it here (fallback, logging, etc.)
  5. } else {
  6.     foreach ($files as $file) {
  7.         // process files
  8.     }
  9. }
Shorter alternative (when you do not need to differentiate false from []):
  1. $files = glob($pattern);
  2. if (empty($files)) {
  3.     // empty ([]) or false
  4. } else {
  5.     foreach ($files as $file) {
  6.         // ...
  7.     }
  8. }

16) Other behaviors that may cause “side effects” (less common)

In PHP 8.2, some smaller changes may cause differences in results for code that depends exactly on return values or data ordering.

str_split("") now returns []

This may affect validations that always expect at least one item in the array.
  1. var_dump(str_split(""));
  2. // PHP 8.2: array(0) { }
  3. // Before: array(1) { [0]=> string(0) "" }

var_export() and fully qualified class names

The var_export() function now exports class names using the fully qualified name (including \), especially when the class is inside a namespace.

This may cause differences in automated tests, snapshots, or string comparisons.

  1. namespace App\Model;

  2. class User {}

  3. echo var_export(new User(), true);
  4. // PHP 8.2: \App\Model\User::__set_state(array(
  5. // ...
  6. // ))

ksort() / krsort() with SORT_REGULAR and numeric strings

In some cases, the order of elements may change when the array keys are numeric strings.
For example, "2" and "10", because they follow the current comparison rules.

  1. $a = ["10" => "dez", "2" => "dois", "1" => "um"];

  2. ksort($a, SORT_REGULAR);
  3. var_dump(array_keys($a));

  4. krsort($a, SORT_REGULAR);
  5. var_dump(array_keys($a));

    • Related Articles

    • How to Generate the Report for PHP Migration

      In order to assist clients who use Scriptcase with an outdated version of PHP (7.0 or 7.3), we have prepared a guide to help with project migration. To assist with the migration, it is necessary to send a report containing some information about the ...
    • Setting environment manually PHP 5.4 - Mac OS X

      We must follow the steps below to perform the installation of php 5.4 on Mac OS X (Mavericks) Run in terminal: sudo curl -s http://php-osx.liip.ch/install.sh | bash -s 5.4 Installation path: /usr/local/php5 Run in the terminal: sudo nano ...
    • Setting environment manually PHP 5.6 - Mac OS X

      We must follow the steps below to perform the installation of php 5.6 on Mac OS X (Mavericks) Run in terminal: sudo curl -s http://php-osx.liip.ch/install.sh | bash -s 5.6 Installation path: /usr/local/php5 Run in the terminal: sudo nano ...
    • Install ScriptCase PHP 7.0 on a XAMPP on Linux

      Xampp Installation Using PHP 7.0 XAMPP It allows you to easily install Apache on your own computer, regardless of your operating system (Linux, Windows, MAC or Solaris). First you have to proceed to download XAMPP PHP ...
    • Updating Scriptcase's PHP

      Currently, the installation of Scriptcase 9.x comes with version 7.0.14 of PHP, unfortunately, this version has a compatibility problem with the new version of authentication of MySQL 8.0, so it is necessary to perform the PHP update so the ...