Intereting Posts

Стратегия для разработки версий с именами и без имен с одним и тем же PHP-кодом

Я поддерживаю библиотеку, написанную для PHP 5.2, и я хотел бы создать версию PHP 5.3-namespaced. Тем не менее, я бы также сохранил версию, отличную от имен, до тех пор, пока PHP 5.3 не станет настолько старым, что даже стабильный сервер Debian отправит его;)

У меня довольно чистый код, около 80 классов, следуя схеме именования Project_Directory_Filename (я бы, конечно, изменил их в \Project\Directory\Filename ) и только несколько функций и констант (также с префиксом имени проекта).

Вопрос в том, что лучше всего разрабатывать параллельные версии с именами и версиями без имен?

  • Должен ли я просто создавать fork в репозитории и сохранять слияние изменений между ветвями? Существуют ли случаи, когда сбрасываемый косой чертой код становится сложным для слияния?

  • Должен ли я писать сценарий, который преобразует версию 5.2 в 5.3 или наоборот? Должен ли я использовать токенизатор PHP? sed ? C препроцессор?

    • Есть ли лучший способ использовать пространства имен, где они доступны, и поддерживать обратную совместимость со старым PHP?


    Обновление: решило отказаться от использования пространств имен .

    Related of "Стратегия для разработки версий с именами и без имен с одним и тем же PHP-кодом"

    Я не думаю, что предварительная обработка кода 5.3 – отличная идея. Если ваш код функционально идентичен как в PHP 5.2, так и 5.3, за исключением использования пространств имен, вместо префиксов, разделенных подчеркиванием, зачем использовать пространства имен вообще? В этом случае мне кажется, что вы хотите использовать пространства имен, ради использования пространств имен.

    Я думаю, вы обнаружите, что при переносе в пространства имен вы начнете «по-разному думать» об организации своего кода.

    По этой причине я полностью согласен с вашим первым решением. Создайте вилку и сделайте резервную копию функций и исправлений.

    Удачи!

    Это продолжение моего предыдущего ответа :

    Код имитации пространства имен был довольно стабильным. Я уже могу заставить symfony2 работать (некоторые проблемы все еще, но в основном). Несмотря на то, что все еще есть недостающее, как разрешение имен имен переменных, для всех случаев, кроме new $class .

    Теперь я написал скрипт, который будет рекурсивно перебирать через каталог и обрабатывать все файлы: http://github.com/nikic/prephp/blob/master/prephp/namespacePortR.php


    Инструкции по использованию

    Требования к работе вашего кода

    Ваши имена классов не должны содержать символ _ . Если они это сделают, классные имена могут быть неоднозначными при преобразовании.

    Ваш код не должен переопределять любые глобальные функции или константы в пространстве имен. Таким образом обеспечивается, что весь ваш код может быть разрешен во время компиляции.

    В основном это единственные ограничения для вашего кода. Хотя я должен отметить, что в конфигурации по умолчанию namespacePortR не будет разрешать такие вещи, как $className = 'Some\\NS\\Class'; new $className $className = 'Some\\NS\\Class'; new $className , потому что для этого потребуется вставить дополнительный код. Лучше, чтобы это было исправлено позже (вручную или с помощью автоматической системы исправления).

    конфигурация

    Поскольку мы сделали предположение о том, что глобальная функция или константа не обновляется в пространстве имен, вы должны установить assumeGlobal класса assumeGlobal в прослушивателе пространства имен . В том же файле установите константу SEPARATOR в _ .

    В namespacePortR измените блок конфигурации, чтобы удовлетворить ваши потребности.


    PS: сценарию может быть предоставлен параметр ?skip=int . Это говорит о том, чтобы пропустить первые int файлы. Это вам не нужно, если вы настроили режим переопределения на интеллектуальный.

    Вот что я нашел:

    Выполнение этого с помощью регулярных выражений – это кошмар. Вы можете получить большинство из них с помощью всего лишь нескольких простых выражений, но тогда крайние случаи – убийца. Я закончил с ужасным, хрупким беспорядком, который едва работает с одной кодовой базой.

    Это выполнимо со встроенным токенизатором и простым рекурсивным парсером спуска, который обрабатывает только упрощенное подмножество языка.

    Я закончил с довольно уродливым дизайном (синтаксический анализатор и трансформатор в одном – в основном только изменяющие или переименование токенов), потому что казалось слишком много работы по созданию полезного синтаксического дерева с сохраненным пробелом (я хотел, чтобы полученный код был удобочитаемым человеком ).

    Я хотел попробовать phc для этого, но не смог убедить его configure что я создал нужную версию библиотеки Boost.

    Я еще не пробовал ANTLR, но это, вероятно, лучший инструмент для таких задач.

    Я работаю над проектом, который эмулирует PHP 5.3 на PHP 5.2: prephp . Он включает поддержку пространства имен (еще не завершена).

    Теперь из опыта написания этой проблемы существует одна проблема двусмысленности в разрешении пространства имен : неквалифицированные вызовы функций и постоянный поиск имеют откат к глобальному пространству имен. Таким образом, вы можете автоматически конвертировать свой код, только если вы либо полностью квалифицировали, либо квалифицировали все свои вызовы функций / постоянный поиск или если вы не переопределили какую-либо функцию или константу в пространстве имен с тем же именем, что и встроенная функция PHP.

    Если вы строго придерживаетесь этой практики (в зависимости от того, какой из них вы выберете), было бы довольно легко преобразовать ваш код. Это будет подмножество кода для эмуляции пространств имен в prephp. Если вам нужна помощь в реализации, я не могу спросить меня, мне было бы интересно;)

    PS: Код эмуляции пространства имен prephp еще не завершен и может быть ошибкой. Но это может дать вам некоторые идеи.

    Вот лучший ответ, который, я думаю, вы сможете найти:

    Шаг 1. Создайте каталог под названием 5.3 для каждого кода w / php5.3 каталога и вставьте в него весь 5.3-специфический код.

    Шаг 2: Возьмите класс, который хотите разместить в пространстве имен, и сделайте это в 5.3 / WebPage / Consolidator.inc.php :

     namespace WebPage; require_once 'WebPageConsolidator.inc.php'; class Consolidator extends \WebpageConsolidator { public function __constructor() { echo "PHP 5.3 constructor.\n"; parent::__constructor(); } } 

    Шаг 3: Используйте стратегическую функцию для использования нового кода PHP 5.3. Место в не-PHP5.3 findclass.inc.php:

     // Copyright 2010-08-10 Theodore R. Smith <phpexperts.pro> // License: BSD License function findProperClass($className) { $namespaces = array('WebPage'); $namespaceChar = ''; if (PHP_VERSION_ID >= 50300) { // Search with Namespaces foreach ($namespaces as $namespace) { $className = "$namespace\\$className"; if (class_exists($className)) { return $className; } } $namespaceChar = "\\"; } // It wasn't found in the namespaces (or we're using 5.2), let's search global namespace: foreach ($namespaces as $namespace) { $className = "$namespaceChar$namespace$className"; if (class_exists($className)) { return $className; } } throw new RuntimeException("Could not load find a suitable class named $className."); } 

    Шаг 4. Перепишите код так, чтобы он выглядел следующим образом:

     <?php require 'findclass.inc.php'; $includePrefix = ''; if (PHP_VERSION_ID >= 50300) { $includePrefix = '5.3/'; } require_once $includePrefix . 'WebPageConsolidator.inc.php'; $className = findProperClass('Consolidator'); $consolidator = new $className; // PHP 5.2 output: PHP 5.2 constructor. // PHP 5.3 output: PHP 5.3 constructor. PHP 5.2 constructor. 

    Это будет работать для вас. Это сложность, но немного, и это будет сделано, когда вы решите отказаться от поддержки 5.3.

    То, что я сделал, с большой базой кода, которая использовала соглашение об именах подчёркивания (среди прочих), и require_once целого множества вместо автозагрузчика, заключалась в определении автозагрузчика и добавлении строк class_alias в файлы, определяющие псевдонимы, к старым именам классов после изменения их имен, чтобы они были хорошими с пространствами имен.

    Затем я начал удалять операторы require_once где выполнение не зависело от порядка включения, поскольку автозагрузчик собирал вещи и вещи пространства имен, когда я исправлял ошибки и так далее.

    До сих пор он работал очень хорошо.

    Ну, я не знаю, является ли это «лучшим» способом, но теоретически вы можете использовать скрипт для переноса вашего кода миграции 5.3 и его резервного копирования в 5.2 (возможно, даже с использованием PHP).

    В ваших файлах пространства имен вы хотели бы что-то сделать:

     namespace \Project\Directory\Filename; class MyClass { public $attribute; public function typedFunction(MyClass $child) { if ($child instanceof MyClass) { print 'Is MyClass'; } } } 

    К чему-то вроде:

     class Project_Directory_Filename_MyClass { public $attribute; public function typedFunction(Project_Directory_Filename_MyClass $child) { if ($child instanceof Project_Directory_Filename_MyClass) { print 'Is MyClass'; } } } 

    И в вашем коде пространства имен вам нужно будет конвертировать из:

     $myobject = new Project\Directory\Filename\MyClass(); 

    Для того, чтобы:

     $myobject = new Project_Directory_Filename_MyClass(); 

    Хотя все ваши требования и requires будут оставаться неизменными, я думаю, вам почти нужно будет хранить какой-то кеш всех ваших классов и пространства имен, чтобы выполнять сложное преобразование вокруг «instanceof» и типизированных параметров, если вы их используете. Это самая сложная вещь, которую я вижу.

    Я не тестировал это самостоятельно, но вы можете взглянуть на этот скрипт php 5.2 -> php 5.3 .

    Это не то же самое, что 5.3 -> 5.2, но, может быть, вы найдете там что-то полезное.

    Наш инструментарий DMS Software Reengineering Toolkit может, скорее всего, реализовать ваше решение. Он предназначен для обеспечения надежных преобразований исходного кода с использованием преобразований AST в AST, закодированных в терминах поверхностного синтаксиса.

    У него есть PHP Front End, который представляет собой полный, точный парсер PHP, AST-строитель и AST для регенератора PHP-кода. DMS обеспечивает трафаретную печать AST или печать верности («по возможности сохранить номера столбцов»).

    Эта комбинация была использована для реализации множества надежных инструментов для PHP-кода для PHP 4 и 5.

    EDIT (в ответ на несколько недоверчивый комментарий):

    Для решения OP необходимо выполнить следующее правило преобразования DMS:

     rule replace_underscored_identifier_with_namespace_path(namespace_path:N) :namespace_path->namespace_path "\N" -> "\complex_namespace_path\(\N\)" if N=="NCLASS_OR_NAMESPACE_IDENTIFIER" && has_underscores(N); 

    Это правило находит все «простые» идентификаторы, которые используются там, где допускаются пути пространств имен, и заменяет эти простые идентификаторы на соответствующий путь пространства имен, построенный путем разрыва строки для идентификатора отдельно на единичные элементы, разделенные символами подчеркивания. Нужно закодировать некоторую процедурную помощь в реализации LANDAGE DMS, PARLANSE, чтобы проверить, что идентификатор содержит символы подчеркивания («has_underscores»), и реализовать логику разрыва, построив соответствующее поддерево пути пространства имен («complex_namespace_path»).

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

    Логика приложения правил DMS может тривиально применять это правило повсюду в AST, создаваемом парсером PHP.

    Этот ответ может показаться чересчур простым перед лицом всех сложных вещей, которые составляют PHP langauge, но вся эта сложность скрыта в определении langauge PHP, используемом DMS; это определение составляет около 10 000 строк лексических и грамматических определений, но уже проверено и работает. Все машины DMS и эти линии 10K являются признаками того, почему простые регулярные выражения не могут выполнять работу надежно. (Удивительно, сколько машин требуется, чтобы получить это право, я работаю над DMS с 1995 года).

    Если вы хотите увидеть все механизмы, которые определяют, как DMS определяет / манипулирует языком, вы можете увидеть хороший простой пример .