миграция — порядок обработки переменных: изменения в PHP 7

С выходом нового PHP 7.0.0 я немного обеспокоен изменениями в порядке оценки так называемых «переменных переменных».

На эта страница, в разделе «Изменения в обработке переменных» отображается таблица с примерами выражений с порядком их обработки в PHP 5 и PHP 7. Перечислены четыре выражения:

$$foo['bar']['baz']
$foo->$bar['baz']
$foo->$bar['baz']()
Foo::$bar['baz']()

Учитывая следующую строку и массив:

$qux = 'quux';
$foo = array('bar' => array('baz' => 'qux'));

первое выражение в таблице $$foo['bar']['baz'] интерпретируется в PHP 5 как значение переменной, названной как значение в $foo['bar']['baz']Таким образом, значение $qux, который 'quux',

Тем не менее, в PHP 7, насколько я понимаю, это же выражение будет интерпретироваться как переменная, названная как значение в $fooТаким образом, я ожидаю, что PHP-уведомление для преобразования массива в строку, так как $foo это массив.

Другие примеры в таблице, кажется, являются вариацией этой же темы.

Конечно, мне любопытно, почему это изменилось в PHP 7 (в частности, почему это изменение важнее, чем обратная совместимость), однако, этот вопрос не подходит для SO. Мой вопрос более практичный:

Каков был бы рекомендуемый способ справиться с этой несовместимостью?

Конечно, добавление фигурных скобок в оскорбительные выражения поможет (${$foo['bar']['baz']}, $foo->{$bar['baz']}, $foo->{$bar['baz']}() а также Foo::{$bar['baz']}()), но это очень громоздко, просматривая тонны старого кода, ища относительно немного случаев …

Иначе, являются ли эти четыре примера единственно возможными вариациями синтаксиса? То есть я могу создать RegExp и grep весь обидный код? Какие еще варианты могут существовать?

2

Решение

Расмус Лердорф написал инструмент статического анализа, который может выявить эти так называемые проблемы с унифицированным переменным синтаксисом, которые называются Phan https://github.com/etsy/phan

Фан имеет возможность -b, --backward-compatibility-checks проверить наличие потенциальных проблем с PHP 5 -> PHP 7 BC.

5

Другие решения

https://wiki.php.net/rfc/uniform_variable_syntax

У вас действительно нет выбора, кроме как перефакторировать их вручную. Если вы не можете придумать регулярное выражение, чтобы найти применение синтаксису переменных переменных.

По поводу причины «почему». Синтаксис единой переменной позволяет нам использовать свойства структур данных (например, индексы массива и возвращаемые значения) так же, как мы используем цепочку методов объекта.

Изменение порядка приоритета переменной переменной было жертвой этого улучшения. Стоит это по моему мнению.

0

Вам просто нужно найти все экземпляры $$, ::$ а также ->$ и добавьте фигурные скобки, где это необходимо:

find . -name "*.php"  -exec grep -l '\->\$' {} \;|while read f; do
echo $f;  grep -H '\->\$' $f ;
# do some sed magic here to add braces
done

find . -name "*.php"  -exec grep -l '\$\$\w*\[' {} \;|while read f; do
echo $f;  grep -H '\$\$\w*\[' $f ;
# do some sed magic here to add braces
done

find . -name "*.php"  -exec grep -l '::\$' {} \;|while read f; do
echo $f;  grep -H '::\$' $f ;
# do some sed magic here to add braces
done

Может быть, кто-то знает право sed синтаксис, поэтому я добавлю его здесь.

Я уже закомментировал экземпляры указателя & перед объектами с:

find . -name "*.php"  -exec grep -l new {} \;|while read f; do
sed -i -e 's~=\s*\&\s*new~= /*\&*/ new~g' "$f">/tmp/a;
done

Я добавил комментарии вместо того, чтобы просто удалить &, чтобы иметь возможность решать ошибки, которые могут возникнуть позже.

0

Шаг 1, Нахождение выражения проблемы

Это слишком трудно найти с помощью grep и некоторое магическое регулярное выражение, потому что у него много факторов.

Phan https://github.com/etsy/phan можно решить, с опцией -b, --backward-compatibility это проверяет потенциальные проблемы PHP 5 -> PHP 7 BC. Это может быть немного тяжелым, потому что это ищет общие проблемы.

Если вам нужен инструмент без конфигурации, вы можете попробовать

PHP-миграции https://github.com/monque/PHP-Migration.

Будет разбирать код дважды, сначала как PHP 7, потом второй PHP 5. Затем сравните узлы в результате AST, если обнаружится какое-либо различие, означает, что при его запуске между PHP 5/7 произойдет другое поведение, так что вы можете перейти к строке, сообщенной этим инструментом, и проверьте код вручную.

$ cat demo.php
<?php

$$foo['bar']['baz'];
$foo->$bar['baz'];
$foo->$bar['baz']();
Foo::$bar['baz']();

$ php bin/phpmig demo.php

File: demo.php
--------------------------------------------------------------------------------
Found 4 spot(s), 4 identified
--------------------------------------------------------------------------------
3 | WARNING    | * | 7.0.0 | Different behavior between PHP 5/7
4 | WARNING    | * | 7.0.0 | Different behavior between PHP 5/7
5 | WARNING    | * | 7.0.0 | Different behavior between PHP 5/7
6 | WARNING    | * | 7.0.0 | Different behavior between PHP 5/7
--------------------------------------------------------------------------------

Шаг 2, Почини это

Теперь у вас есть список, содержащий файл и номер строки, которые вы должны исправить.

1, исправить вручную, проверить внимательно рекомендуемые

2, генерировать код с помощью PHP-парсер PrettyPrinter

<?php

use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;

// Parse in PHP 5 mode
$parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP5);
$printer = new PrettyPrinter\Standard();

$code = <<<'EOC'
<?php

$$foo['bar']['baz'];
$foo->$bar['baz'];
$foo->$bar['baz']();
Foo::$bar['baz']();
EOC;

$stmts = $parser->parse($code);
$code = $printer->prettyPrintFile($stmts);
echo $code."\n";
0
По вопросам рекламы [email protected]