Home > ant, программирование > Как я склеиваю Zend Framework

Как я склеиваю Zend Framework

Часто надо собрать Zend Framework в одни файл, при этом удалить все require и include. На просторах интернета есть собранные все файлы этого фреймворка, но, иногда, надо собрать только малую часть. Пока, я не нашёл скрипта, чтобы делать один файл да и хотелось этот процесс интегрировать с системой сборки проекта. Так как я использую для сборки Ant, то решил написать скрипт для него. Тем более это оказалось легче, чем предполагал. Тяжело было разобраться с самим Ant`ом ;)

Начало

Создадим основной файл XML для Ant`а с одной целью target и именем name=”concat.zend”. Так же в project укажем основную цель для Анта concat.zend:

<?xml version="1.0"?>
<project name="zend" default="concat.zend" basedir="./../">
    <target name="concat.zend" description="concat ZF files">
    </target>
</project>

В этой цели будем склеивать все файлы в один. Но это не единственная задача. Как минимум, надо ещё одну, которая вырежет все require и include. Но закончим с этой. Дабы не писать пути по несколько раз, введём в проект константу, в которой укажем путь к файлам ZF.

    <property name="library" location="./../library/"/>

Это свойство ставим перед определением целей, чтобы с любой цели иметь доступ к константе. Теперь склеим нужные нам файлы ZF в один.

    <target name="concat.zend" description="concat ZF files">
        <concat destfile="${build}/classes/Ext/Production/Zend.tmp.php">
            <filelist dir="${library}/">
                <file name="Zend/Cache/Backend.php"/>
                <file name="Zend/Cache/Backend/ExtendedInterface.php"/>
                <file name="Zend/Cache/Backend/Interface.php"/>
                <file name="Zend/Db/Exception.php"/>
                <file name="Zend/Db/Adapter/Abstract.php"/>
                <file name="Zend/Db/Adapter/Pdo/Abstract.php"/>
                <file name="Zend/Db/Adapter/Pdo/Mysql.php"/>
                <file name="Zend/Db/Adapter/Exception.php"/>
                <file name="Zend/Db/Table/Abstract.php"/>
                <file name="Zend/Db/Table/Exception.php"/>
                <file name="Zend/Db/Profiler.php"/>
                <file name="Zend/Db.php"/>
                <file name="Zend/Exception.php"/>
                <file name="Zend/Mime.php"/>
                <file name="Zend/Mime/Part.php"/>
                <file name="Zend/Mime/Message.php"/>
                <file name="Zend/Mail.php"/>
                <file name="Zend/Mail/Transport/Abstract.php"/>
                <file name="Zend/Mail/Transport/Sendmail.php"/>
                <file name="Dklab/Cache/Backend/TagEmuWrapper.php"/>
            </filelist>
        </concat>
    </target>

Это соберет нужные классы в файл ${build}/classes/Ext/Production/Zend.tmp.php. ${build} – папка для сборки проекта.

Удаляем require и всё лишнее

Если взглянуть в ${build}/classes/Ext/Production/Zend.tmp.php, то можно увидеть, что это не валидный файл php. Там встречаются <?php много да и зендовские require портят жизнь. Создадим другую цель и удалим это с файла.

    <target name="modify.zend" description="modify ZF files">
        <replaceregexp byline="true" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="^&lt;\?php$"/>
            <substitution expression=""/>
        </replaceregexp>
        <replaceregexp byline="true" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="^\?&gt;"/>
            <substitution expression=""/>
        </replaceregexp>
        <replaceregexp byline="true" flags="smi" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="(require|include)(_once)+( )?(['&quot;])?Zend\/(.*)(['&quot;])?"/>
            <substitution expression=""/>
        </replaceregexp>
        <replaceregexp byline="false" flags="gs" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="/\*.+?\*/"/>
            <substitution expression=""/>
        </replaceregexp>
    </target>

В первом блоке удаляются ВСЕ <?php, потом – ?>, далее все require и include, а под занавес – комментарии. Это сделано с помощью регулярных выражений и если ещё почитать в документации, то всё становится понятным. Теперь надо с цели concat.zend вызвать modify.zend. Это делается в concat.zend с помощью конструкции

        <antcall target="zend.modify.zend" />

Что такое Fake.php

Как известно, в предыдущей цели мы удалили <?php … ?>. Но ведь они то нам надо! Я даже не разбирался, как вставить в файл, а решил просто создать фальшивый файл Fake.php и приклеить перед нашим файлом в цели concat.zend.

        <concat destfile="${build}/classes/Ext/Production/Zend.php">
            <filelist dir="${build}/classes/Ext/Production/" files="Fake.php" />
            <filelist dir="${build}/classes/Ext/Production/" files="Zend.tmp.php" />
        </concat>

Подметаем и заканчиваем

Всё, кажется. Осталось удалить промежуточный файл и насладится работой скрипта:

        <delete file="${build}/classes/Ext/Production/Zend.tmp.php" />

Полная версия XML

<?xml version="1.0"?>
<project name="zend" default="concat.zend" basedir="./../">
    <!-- set global properties for this build -->
    <property name="library" location="./../library/"/>

    <target name="concat.zend" description="concat ZF files">
        <concat destfile="${build}/classes/Ext/Production/Zend.tmp.php">
            <filelist dir="${library}/">
                <file name="Zend/Cache/Backend.php"/>
                <file name="Zend/Cache/Backend/ExtendedInterface.php"/>
                <file name="Zend/Cache/Backend/Interface.php"/>
                <file name="Zend/Db/Exception.php"/>
                <file name="Zend/Db/Adapter/Abstract.php"/>
                <file name="Zend/Db/Adapter/Pdo/Abstract.php"/>
                <file name="Zend/Db/Adapter/Pdo/Mysql.php"/>
                <file name="Zend/Db/Adapter/Exception.php"/>
                <file name="Zend/Db/Table/Abstract.php"/>
                <file name="Zend/Db/Table/Exception.php"/>
                <file name="Zend/Db/Profiler.php"/>
                <file name="Zend/Db.php"/>
                <file name="Zend/Exception.php"/>
                <file name="Zend/Mime.php"/>
                <file name="Zend/Mime/Part.php"/>
                <file name="Zend/Mime/Message.php"/>
                <file name="Zend/Mail.php"/>
                <file name="Zend/Mail/Transport/Abstract.php"/>
                <file name="Zend/Mail/Transport/Sendmail.php"/>
                <file name="Dklab/Cache/Backend/TagEmuWrapper.php"/>
            </filelist>
        </concat>
        <antcall target="zend.modify.zend" />

        <concat destfile="${build}/classes/Ext/Production/Zend.php">
            <filelist dir="${build}/classes/Ext/Production/" files="Fake.php" />
            <filelist dir="${build}/classes/Ext/Production/" files="Zend.tmp.php" />
        </concat>
        <delete file="${build}/classes/Ext/Production/Zend.tmp.php" />
    </target>

    <target name="modify.zend" description="modify ZF files">
        <replaceregexp byline="true" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="^&lt;\?php$"/>
            <substitution expression=""/>
        </replaceregexp>
        <replaceregexp byline="true" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="^\?&gt;"/>
            <substitution expression=""/>
        </replaceregexp>
        <replaceregexp byline="true" flags="smi" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="(require|include)(_once)+( )?(['&quot;])?Zend\/(.*)(['&quot;])?"/>
            <substitution expression=""/>
        </replaceregexp>
        <replaceregexp byline="false" flags="gs" file="${build}/classes/Ext/Production/Zend.tmp.php">
            <regexp pattern="/\*.+?\*/"/>
            <substitution expression=""/>
        </replaceregexp>
    </target>
</project>
  1. May 1st, 2011 at 15:45 | #1

    привет. как ты решил проблему с autoload? решил тоже попробовать оптимизировать ЗФ, собрал все нужные классы в один файл (где-то вычитал, что это гораздо быстрее, чем куча require_once), и все бы ничего, но не могу заткнуть нативный аутолоад зенда.
    то есть, делаю require_once своего большого файла с зендовскими классами, далее запускается бутсрап
    application->bootstrap();
    после этого запускается само приложение
    application->run();
    и тут видимо аутолоад пытается подгрузить уже существующие классы, в результате райзится ошибка

    Fatal error: Cannot redeclare class Zend_View_Helper_Interface in Z:\workspace\mysite\library\Zend\View\Helper\Interface.php on line 30

  2. May 3rd, 2011 at 12:47 | #2

    @heximal
    а Вы с этого большого склееного класса поубирали все require? И я не использую Зендовский Аутолоадер, с ним больше мороки чем толку

  3. May 3rd, 2011 at 13:07 | #3

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

  4. May 3rd, 2011 at 13:21 | #4

    @heximal
    попробуйте выключить его перед запуском бутстрапа

    spl_autoload_unregister(array(‘Zend_Loader_Autoloader’,'autoload’));

  5. May 3rd, 2011 at 13:50 | #5

    делал я такое.
    все-равно ошибка redeclare class вылазит. значит, дело не аутолоадере? а в чем еще может быть? так неохота ползти в дебри зенда…

  6. May 3rd, 2011 at 17:15 | #6

    а вы когда склеивали, смотрели на то, что родительский класс был ранее объявлен, чем дочерний?

  7. May 3rd, 2011 at 21:15 | #7

    да, это я учел (при этом ошибка выглядела class XXX unefined).
    как вы собирали список необходимых файлов с классами?
    я делал так:
    у меня есть AbstractController, от которого наследуются все остальные контроллеры. В нем объявлен метод preDispatch, который вызывается зендом перед тем, как будет произведена диспетчирезация действия (будет вызван соответствующий метод xxxAction). Внутри этого метода я делаю нечто
    $c=get_included_files();
    file_put_contents(“classes_included.txt”, implode(“\n”, $c));
    таким образом, побродив по всем разделам сайта я собираю все используемые файлы зенда.
    Только вот теперь у меня закралось подозрение, что не в том месте я это делаю. После этого еще как минимум запускается рендеринг Layout’а, а там еще куча классов может подключаться. Щас буду изучать.

  8. May 3rd, 2011 at 21:42 | #8

    Все, я его победил! Все стало летать. И хотя считается, что автозагрузка у зенда является образцом оптимизации, я имею устойчивое мнение, что require_once кучи маленьких файлов выполняется гораздо дольше, чем один большой php-файл.
    Thank you for your assistance))

    ЗЫ. Советую также посмотреть в сторону байт-кэширования (напр. APC или eAccelerator). Производительность возрастает в десятки раз.

  9. May 3rd, 2011 at 21:47 | #9

    я сделал проще. Я заставил все классы загружать своим лоадером, а в нём при загрузки чего либо, писал в лог. Потом дело техники – агрегация классов и формирование списка для Анта ) Если вам надо весь фреймфорк – собирайте всё скопом или воспользуйтесь сервисами сборки ZF ( http://epic.codeutopia.net/pack/library/1.10.6 )

  10. May 3rd, 2011 at 21:52 | #10

    heximal :

    Все, я его победил! Все стало летать. И хотя считается, что автозагрузка у зенда является образцом оптимизации, я имею устойчивое мнение, что require_once кучи маленьких файлов выполняется гораздо дольше, чем один большой php-файл.

    Вы правы. Даже банальная загрузка не через require_once, а require даёт большой прирост. Интерпритатор ещё проверяет в памяти, загружал ли он этот файл или нет.

    heximal :

    ЗЫ. Советую также посмотреть в сторону байт-кэширования (напр. APC или eAccelerator). Производительность возрастает в десятки раз.

    ТОже правы. Это аксиома ) ТОлько в APC есть проблема в обновлении кэша, но это вас накроет чуточку попожже ;)

  1. No trackbacks yet.