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](https://static.zohocdn.com/zoho-desk-editor/static/images/quote.png/)

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](https://static.zohocdn.com/zoho-desk-editor/static/images/quote.png/)

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](https://static.zohocdn.com/zoho-desk-editor/static/images/quote.png/)

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](https://static.zohocdn.com/zoho-desk-editor/static/images/quote.png/)

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 = "";
3. $tab = array(
4. 0 => array('tp' => 1, 'vl' => 'aaa'),
5. 1 => array('tp' => 2, 'vl' => 'bbb'),
6. 2 => array('tp' => 3, 'vl' => 'ccc')
7. );
9. while (list($key, $val) = each($tab)) {
10. $result .= $tab[$key]["vl"];
11. }

**✅ Recommended approach (using foreach()):**

1. $result = "";
3. $tab = array(
4. 0 => array('tp' => 1, 'vl' => 'aaa'),
5. 1 => array('tp' => 2, 'vl' => 'bbb'),
6. 2 => array('tp' => 3, 'vl' => 'ccc')
7. );
9. foreach ($tab as $key => $val) {
10. $result .= $tab[$key]["vl"];
11. }

## 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](https://static.zohocdn.com/zoho-desk-editor/static/images/quote.png/)

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. *}*

### **Recommended adjustment:**

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;*
3. *class User {}*
5. *echo var\_export(new User(), true);*
6. *// PHP 8.2: \App\Model\User::\_\_set\_state(array(*
7. *// ...*
8. *// ))*

### ***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"];*
3. *ksort($a, SORT\_REGULAR);*
4. *var\_dump(array\_keys($a));*
6. *krsort($a, SORT\_REGULAR);*
7. *var\_dump(array\_keys($a));*