Zend Framework: оптимизация Zend_View, и нужен ли нам Zend_Cache?

Zend Framework

Для тех кто уже хоть чуть-чуть знаком с Zend_View не будет секретом существование Helper’ов – классов которые облегчают генерацию HTML кода. Написать свой helper не составит труда даже для начинающего разработчика, но я решил покопаться внутри и понять, а все ли коту масленица.

Zend_View: Helpers

И так, для начала поясню как работает механизм вызова helper’ов:

В классе Zend_View_Abstract существует магический метод __call (о принципах работы см. документацию) , при вызове данного метода, происходит следующее:

  • Проверяется не был ли загружен класс вызываемого helper’a до этого
  • Если не был загружен – пытаемся найти и прочитать файл во всех путях к helper’ам (мы их можем добавлять используя метод addHelperPath)
  • Нашли, проинклудили, создали сущность класса, сохранили для потомков
  • У объекта helper’a вызываем необходимый нам метод

Ну как Вам сила ООП? И все это сверху прикрыто еще множеством проверок, т.е. для вызова одного метода выполняется очень много телодвижений.

Что я предлагаю? Создайте свой класс View, который будет наследоваться от Zend_View_Abstract, и добавьте все необходимые методы в данный класс. Этот вариант более предпочтителен если Ваши хэлперы не слишком громоздки.

Вот что у меня получилось когда я helper для translate перекинул в свой XCore_View объект (данные для 10000 идентичных вызовов):

Time (s) Memory (b)
Метод во View 0.3108 0122416
View Helper 0.5231 0124116
Разница 0.2123 0001700

Как видим различия в использованной памяти ничтожно малы, но вот время выполнения скрипта страдает, конечно я понимаю что 10 000 вызовов на страницы не будет, но осадочек то остается…

Причина более медленной работы ZF кроется во множестве проверок, т.е. мой код по идеи менее дуракоустойчив…

Далее – в версии 1.5 добавили еще несколько хэлперов для формирования заголовков в HTML документе:

  • Doctype
  • HeadLink
  • HeadMeta
  • HeadScript
  • HeadStyle
  • HeadTitle
  • InlineScript

Ранее для этой цели мной был написан класс Document, но поскольку стремление быть ближе к ZF было велико, решил я использовать хэлперы и забыть о классе Document. Но я опять столкнулся с проблемой производительности (Init – время и память потраченные на инициализацию, Output – генерация HTML):

Time (s) Memory (b)
Init Output Init Output
Старый Document 0.0003 0.0083 0004288 0108008
View Helpers 0.0054 0.0105 0166624 0122984
Разница 0.0051 0.0022 0162336 0014976

Немного поясню результаты – при инициализации helper’ов происходит поиск и загрузка нужных файлов, и так же создается сущность объекта для каждого из helper’ов. При использовании же класса Document, мы оперируем только одним файлом, одним классом, одним объектом. При выводе результаты не отличаются так сильно – что и не удивительно – происходит всего-лишь вызов методов уже существующих в памяти объектов, которые выполняют практически идентичные задачи.

Zend_Cache

Еще хотел бы похвалить удобство работы с Zend_Cache, но вот скорость работы опять же уступает кастомному решению:

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

function getConfig() {
  require_once 'Zend/Cache.php';
  $frontendOptions = array('master_file' => 'config.xml' , 'automatic_serialization' => true , 'lifetime' => null , 'write_control' => false);
  $backendOptions  = array('cache_dir' => 'config' , 'file_locking' => false);// FIXME: it's ZF error

  $cache = Zend_Cache::factory('File', 'File', $frontendOptions, $backendOptions);

  if (! ($parsed = $cache->load(md5('config.xml')))) {
            // load configuration file
            $parsed = simplexml_load_file($xml_path, "XCore_XML_Element", LIBXML_NOCDATA);
            $cache->save($parsed);
        }
  }
  return $parsed;
}

Опять же заглянув внутрь – не все то самолет, что Zend Framework:

Для контроля изменений мастер-файла в кэш директории Zend создает 2 файла – сам кэш данных – представляющий собой серелизованный массив и еще один файл содержащий мета данные о оригинальном файле включая настройки кэширования. Т.е. когда у нас выполняется проверка на попадание в кэш – всегда считывается файл с метаданными и десерелизуется, а на это тратиться время. Попробуем написать свой механизм кэширования файлов, используя в качестве средства контроля изменений лишь дату модификации файла, вот каков результат (тестирование при попадании в кэш):

Time (s) Memory (b)
Xcore_Cache_Config 0.0015 0057076
Zend_Cache 0.0030 0101096
Разница 0.0015 0044020

Да уж – тут становиться грустно – разница почти в два раза, радует что в системе зачастую не бывает более одного конфигурационного файла, хотя у кого как – у нас в phpXcore их 5, хорошо это или плохо, не знаю…

А в целом использовать Zend_Cache удобно, и зачастую необходимо…

P.S. Продуктивный день – покритиковал Zend, похвалил Microsoft, день прошёл не зря, но у меня ощущение, что сделал я что-то не так…

14 thoughts on “Zend Framework: оптимизация Zend_View, и нужен ли нам Zend_Cache?”

  1. Спасибо, отличная статья.
    Сам использую ZF для проектов со средней нагрузкой. бля большей нагрузки, увы, пока не смог приспособить….

  2. А собственно чего вы ожидали?
    Что common-решение из какого-либо фреймворка будет работать оптимальнее заточенного под конкретные нужды?
    В принципе то что вы описали сплошь и рядом – в любом фреймворке на любом языке.

  3. Иного, лично я, и не ожидал, ИМХО : любое кастомное решение быстрее любого универсального, но необходимо помнить, что в OpenSource проекты вложено много человеко-часов, и только Вам решать – есть ли у Вас возможность писать собственное решение для поставленной задачи, или все же воспользоваться сторонней библиотекой, жертвуя производительностью…

  4. У автора видно одно рвение использовать все компоненты ZF, а по самой идеи ZF на столько гибок и разработан с учетом того что позволяет использовать любые свои компоненты отдельно друг от друга.

    p/s
    Проблема php как ни странно не в быстроте работы, а как кажется в том что это блокнотный язык программирования, которые не требует спец ide и так дальше, в этом его и сила и беда. :)

  5. to Роман:
    Такого рвения у меня нет, в проекте phpXCore моя команда использует ZF именно по отдельности, мы не используем их реализацию MVC, ибо нам она не нравиться, из всех компонентов активно используется Acl, Cache, Translate и View (может еще чего)

  6. 2 Роман
    люблю к словам поцепляться – а какой язык требует “спец ide и так дальше”? я так кроме пролога и не вспомню…

  7. А все таки как решить проблемы оптимизации наиболее общим способом не опускаясь до деталей? Я на хабре видел идею с объединением файлов зенда в один или eaccelerator. А вы к чему-нибудь пришли?

    ps. Когда пишешь комментарий, то adsense с котенком справа закрывает область для ввода текста. IE 6.0

  8. Общим способом – это прикрутка различных акселераторов и внедрения кэша на уровне приложения (к примеру Zend_Cache), как либо иных общих способов я не вижу…
    P.S. Кота в скором времени уберу, как всю иную рекламу на блоге, IE – это зло :) …

  9. Случайно заглянул еще раз прочитал стать,
    хм, чем вас не устроило решения ZF с хелпарами?
    ведь для того чтоб создать новый хелпер вам не нужно открыть файл и редактировать его, вы просто создаете новый файл и вауля, это вы и сами понимаете, просто удобство как мне кажется именно в этом,
    на счет Zend_Controller согласен я вспоминаю версии 0.2 – 0.3 это было практически основа каркас в действительности, сейчас это более похоже на мини
    монстра. :)
    Товарищ спрашивал какое мне ide или язык нужен, скажу свою мини мечту ide уровня vs 2008 с полной поддержкой php + фреемворк к нему уровня .net
    p/s
    Я знаю есть плагин под vs2008 для php но это не то, от buildera тоже не самолет далеко. :)

  10. to Роман:
    Мне решение с хэлперами нравиться, и даже очень, но по факту, если переусрдствовать с ними, получим проблемы с производительностью, именно эту мысль хотел донести до моих читателей…
    Насчет IDE – я однозначно сейчас подсел на Zend Studio 6.0 – которая в действительность есть Eclipse, а в комплекте с Aptana удовлетворяет всем моим запросам…

  11. Проблем с производительность минимальны посравнению с тем,что дает зенд в плане разработки. Решаются проблемы с помощью кэширования либо Zend_Cache or memcached (дает ощутимый прирост) на уровне приложения, на уровне БД – это использование процедур, представлений и триггеров, на уровне сервера – это nginx и другие вариации (сис-админы просветят лучше).
    При нормальной архитектуре + всякие оптимизаторы и акселераторы мы получим очень хорший эффект.

  12. Немного выскажусь, не смог пройти мимо.

    Да, кастомное решение быстрее в каждом конкретном случае, но есть два “но”:
    1. При небольшой посещаемости разница в нагрузке не скажется никак. Можно сказать, что при невысокой нагрузке на разработанный сервис разницы между кастомным решением и использованием ZF нет. При этом есть вопрос безопасности, не уверен, что в кастомном решении будет все так же хорошо, как в ZF.
    2. При высокой нагрузке проект чаще всего развивается динамично и через год напряженной работы коллектива програмистов “кастомное решение” превращается в лоскутное одеяло, которое обеспечит массу проблем. ZF же дает гибкость разработки и это его главное преимущество.

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

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

Comments are closed.