Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

LdCoding's avatar

How to resolve a PHP regex search and replace which breaks when adding single quote inside single quoted strings?

I'm currently working on a PHP project that was recently upgraded from PHP 7.1 to PHP 7.2. After the upgrade, we've been seeing warnings related to array keys that are not enclosed in quotes.

In PHP 7.2, the E_WARNING error level was raised for cases where array keys were not enclosed in quotes. Specifically, when a string literal or an unquoted string is used as an array key, PHP 7.2 issues a warning similar to the following:

Warning: Use of undefined constant mykey - assumed 'mykey' (this will throw an Error in a future version of PHP)

The warning message indicates that the string "myKey" is being treated as a constant, which may lead to errors in the future. This warning was introduced as part of the effort to make PHP code more reliable and to prevent common sources of errors.

To address this, I found a regex that can identify and fix array keys that are not wrapped in quotes and replaces the content of the array keys with single quotes:

$fileContent = preg_replace('/^!|$([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\[([a-zA-Z_][a-z0-9_]+)\]/','$[\'\']', $fileContent, -1, $c1);

However, I noticed that the regex matches array keys that are within single quoted strings and causes a syntax error after wrapping it in single quotes. For example:

before : 'some string $var[testkey4]; around the var';

after : 'some string $var['testkey4']; around the var'; syntax error, unexpected 'testkey4' (T_STRING)

How can I resolve this ?

0 likes
5 replies
LaryAI's avatar
Level 58

To resolve this issue, you can modify the regular expression to exclude array keys that are already enclosed in single quotes. Here's an updated regex that should work:

$fileContent = preg_replace('/^!|$([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\[(?<!\')([a-zA-Z_][a-z0-9_]+)(?!\')\]/','$[\'\']', $fileContent, -1, $c1);

The key difference is the addition of negative lookbehind and negative lookahead assertions to exclude array keys that are already enclosed in single quotes. Specifically, the (?<!\') assertion checks that the opening bracket is not preceded by a single quote, and the (?!\') assertion checks that the closing bracket is not followed by a single quote.

With this modification, the regex should only match array keys that are not already enclosed in single quotes, and should not cause syntax errors when replacing them with quoted keys.

Note that this solution assumes that array keys are only enclosed in single quotes, and not double quotes or backticks. If your code uses other types of quotes for array keys, you may need to modify the regular expression accordingly.

tisuchi's avatar

@ldcoding How about this?

$fileContent = preg_replace_callback('/[a-zA-Z_][a-zA-Z0-9_]+\[([a-zA-Z_][a-z0-9_]+)\]/',
    function ($matches) {
        if (preg_match('/^\'.*\'$/', $matches[0])) {
            return $matches[0];
        } else {
            return '$[\'' . $matches[1] . '\']';
        }
    },
    $fileContent,
    -1,
    $c1
);
tisuchi's avatar

@LdCoding This code is using the preg_replace_callback function in PHP to perform a regular expression search and replace on the contents of the $fileContent string. The regular expression being used is /[a-zA-Z_][a-zA-Z0-9_]+\[([a-zA-Z_][a-z0-9_]+)\]/ and it matches strings that follow the pattern of [a-zA-Z_][a-zA-Z0-9_]+\[([a-zA-Z_][a-z0-9_]+)\].

The second argument to the preg_replace_callback function is a closure (an anonymous function) that takes in an array of matches found by the regular expression. The closure checks if the first match (stored in $matches[0]) is surrounded by single quotes (using the preg_match function and the regular expression /^\'.*\'$/). If it is, the closure returns the original match ($matches[0]). If it is not, the closure returns a string with single quotes around the second match (stored in $matches[1]) and surrounded by $[''].

The fourth argument to the preg_replace_callback function specifies the maximum number of replacements to make and is set to -1, meaning all matches will be replaced. The fifth argument, $c1, is an optional argument that stores the count of replacements made.

The final result of this code is that the $fileContent string will have any non-quoted array keys within it wrapped in single quotes and surrounded by $[''].

sarafoster's avatar

To resolve a PHP regex search and replace that breaks when adding single quotes inside single quoted strings, you can either use double quotes instead of single quotes for your regex pattern, or you can escape the single quote character inside your single quoted string.

For example, if you have a regex pattern like this using single quotes: https://www.homebargainsportal.com/

$pattern = '/regex pattern with single quote inside/';

$pattern = '/regex pattern with single 'quote' inside/';

$pattern = "/regex pattern with single quote inside/";

Please or to participate in this conversation.