<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>Blog entries tagged symfony :: mwop.net</title>
    <description>Blog entries tagged symfony :: mwop.net</description>
    <pubDate>Fri, 14 Jan 2011 08:53:52 -0600</pubDate>
    <generator>Laminas_Feed_Writer 2 (https://getlaminas.org)</generator>
    <link>https://mwop.net/blog/tag/symfony</link>
    <atom:link rel="self" type="application/rss+xml" href="https://mwop.net/blog/tag/symfony/rss.xml"/>
    <item>
      <title>Aspects, Filters, and Signals, Oh, My!</title>
      <pubDate>Fri, 14 Jan 2011 08:53:52 -0600</pubDate>
      <link>https://mwop.net/blog/251-aspects-filters-and-signals-oh-my.html</link>
      <guid>https://mwop.net/blog/251-aspects-filters-and-signals-oh-my.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>Last month, during <a href="http://phpadvent.org">PHP Advent</a>, <a href="http://ohloh.net/accounts/gwoo">gwoo</a> wrote an interesting post on <a href="http://phpadvent.org/2010/aspect-oriented-design-by-garrett-woodworth">Aspect-Oriented Design</a>, or Aspect Oriented Programming (AOP) as it is more commonly known. The article got me to thinking, and revisiting what I know about AOP, Intercepting Filters, and Signal Slots -- in particular, what use cases I see for them, what the state of current PHP offerings are, and where the future may lie.</p>
<p>But first, some background is probably in order, as this is a jargon-heavy post.</p>


<h2>Aspect Oriented Programming</h2>
<p>I was first introduced to AOP in 2006 via an
<a href="http://www.phparch.com/magazine/2006-2/april/">April 2006 php|architect article by Dmitry Sheiko</a>.
That article detailed adding calls at various places in a method where you might
want to hook into functionality — for instance, to log, cache, etc. Expanding
on this, I considered other possibilities: manipulating incoming arguments,
validation, ACL checks, implementing write-through caching strategies, and more.
The approach is daunting, however; typical, naive implementations lead to a lot
of boiler-plate code:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Listener</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">notify</span><span class="hljs-params">($signal, $argv = null)</span></span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $listeners;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attach</span><span class="hljs-params">($signal, Listener $listener)</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;listeners[$signal][] = $listener;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span><span class="hljs-params">($arg1, $arg2)</span>
    </span>{
        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">$this</span>-&gt;listeners <span class="hljs-keyword">as</span> $listener) {
            $listener-&gt;notify(<span class="hljs-string">'preDoSomething'</span>, func_get_args());
        }
        
        <span class="hljs-comment">// do some work</span>
        
        <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">$this</span>-&gt;listeners <span class="hljs-keyword">as</span> $listener) {
            $listener-&gt;notify(<span class="hljs-string">'postDoSomething'</span>, $result);
        }
    }
}
</code></pre>
<p>The article didn't go into any real details on how you might short-circuit the
filters or handle return values from them, and aspect handling itself was not
detailed completely. As such, the code begins to add up, particularly if many
classes and/or methods implement the functionality.</p>
<h2>Intercepting Filters</h2>
<p>A similar concept to AOP is the idea of
<a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html">Intercepting</a>
<a href="http://msdn.microsoft.com/en-us/library/ff647251.aspx">Filters</a>. Like AOP, the
idea is to separate cross-cutting concerns such as logging, debugging, and more
from the actual logic the component exposes. The difference is that typically
Intercepting Filters are language independent, have a standard implementation in
a given framework, and can be re-used. The approach gwoo used in his post falls
more under this category.</p>
<p><a href="http://lithify.me/">Lithium</a>, a PHP 5.3 framework and the reference for gwoo's
article, has a very intriguing approach. Instead of calling the filters
explicitly within the body of the code, they suggest that the body of the code
simply becomes one of the filters, via a closure:</p>
<pre><code class="language-php hljs php" data-lang="php">Dispatcher::applyFilter(<span class="hljs-string">'run'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">($self, $params, $chain)</span> </span>{
    <span class="hljs-comment">// do something...</span>
    <span class="hljs-keyword">return</span> $chain-&gt;next($self, $params, $chain);
});
</code></pre>
<p>In Lithium, each filter is responsible for calling the next (each filter
receives the chain as its third and final argument); as soon as one doesn't call
<code>next()</code>, execution is stopped, and the result returned (or at least that's how
I read the source). You can call the chain either before or after the code you
want to execute in each filter; placement will determine whether it's a pre- or
a post-filter. The approach answers a number of the concerns I outlined
previously — namely, standardization of approach, and the ability to
short-circuit execution.</p>
<p>The above example defines a filter that will run when the <code>run()</code> method of the
<code>Dispatcher</code> class is executed. <code>$self</code> will typically be the object instance,
<code>$params</code> an array of the parameters passed to the method, and <code>$chain</code> as
described above. The method itself will execute any filters — typically with
something like this:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">use</span> <span class="hljs-title">lithium</span>/<span class="hljs-title">core</span>/<span class="hljs-title">Object</span> <span class="hljs-title">as</span> <span class="hljs-title">BaseObject</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseObject</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span><span class="hljs-params">($with, $these, $args)</span>
    </span>{
        $params = compact(<span class="hljs-string">'with'</span>, <span class="hljs-string">'these'</span>, <span class="hljs-string">'args'</span>);
        
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;_filter(<span class="hljs-keyword">__METHOD__</span>, $params, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">($self, $params)</span> </span>{
            <span class="hljs-comment">// do the actual work here</span>
            <span class="hljs-keyword">return</span> $result;
        });
    }
}
</code></pre>
<p>(The <code>_filter()</code> method is defined in <code>lithium\core\Object</code>, and basically
passes a local, static chain of filters to Lithium's <code>Filter</code> class for
execution. <code>applyFilter()</code> from the previous example statically adds a callback
under the named method to the chain.)</p>
<p>This solution is elegant — but I see some limitations:</p>
<ul>
<li>
<p>First and foremost, I'm not particularly fond of the filtering functionality
being via static methods on a single class; it introduces a hard-coded, hidden
dependency. This means you cannot provide alternate filtering functionality
without extending the class <em>consuming</em> the filters, nor without either
extending the base filters implementation should you wish to provide a
compatible API (for instance, to introduce an implementation that understands
priorities).</p>
<p>Additionally, the easiest way to implement filtering in Lithium is by
extending the <code>lithium\core\Object</code> class — I could find no examples
elsewhere in the documentation that showed how you would compose the
<code>Filters</code> implementation in your own objects. As such, the easiest way to
compose filters is now via inheritance, which seems to be
counter-productive to the whole rationale behind filtering, to my thinking.</p>
</li>
<li>
<p>Second, the approach of making the body of the calling method a closure makes
it difficult to create non-public helper methods. Inside the filter, you're no
longer in the scope of the object, losing the semantics that tie the various
metadata and functionality of the object together. (The Lithium docs provide
illustrations of how to accomplish this, but they require extra work, and a
keen understanding of how references work in PHP.)</p>
</li>
<li>
<p>Third, it's sometimes useful to have access to the return results of <em>all</em> the
filters (not just the last executed); you may want to aggregate them in some
way, or branch logic based on the various returns.</p>
</li>
<li>
<p>Fourth, it's sometimes useful to have multiple call points within the main
code. As an example, for many caching strategies, you'd check first to see if
you have a cache hit, and return immediatly if found; otherwise, you'd execute
the code, and cache the result prior to returning it. This might be possible
in Lithium with constructs like this:</p>
<pre><code class="language-php hljs php" data-lang="php">Filters::add(<span class="hljs-string">'SomeClass::doSomething'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">($method, $self, $params)</span> </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">null</span> !== ($content = cache_hit($params))) {
        <span class="hljs-keyword">return</span> $content;
    }
    $content = Filters::next($method, $self, $params);
    <span class="hljs-keyword">return</span> $content;
});
</code></pre>
<p>However, if you have several filters such as this, the order then becomes
paramount, and that introduces new complexities.</p>
<p>Another example would be with façade methods, where you may wish to introduce
filters before and after each method call:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomeWorkflow</span><span class="hljs-params">($message)</span>
</span>{
    <span class="hljs-keyword">$this</span>-&gt;somePrivateMethod($message);
    <span class="hljs-keyword">$this</span>-&gt;nextPrivateMethod($message);
    <span class="hljs-keyword">$this</span>-&gt;lastPrivateMethod($message);
}
</code></pre>
<p>(I can already hear <a href="http://nateabele.com/">Nate</a> saying &quot;make those all
filters!&quot; or &quot;filter each method!&quot; — but that's the problem with simple
examples - they can't always express the nuances of a use case.)</p>
</li>
<li>
<p>Fifth, it's useful to be able to attach callbacks that are not aware of the
chain. For instance, you may have code you've already written that works
perfectly fine in a standalone situation — e.g., a logger — and you simply
want to add it to the chain. In the Lithium paradigm, you'd need to
<a href="http://en.wikipedia.org/wiki/Currying">curry</a> the calls in, instead of simply
using the existing method:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-comment">// This:</span>
SomeClass::applyFilter(<span class="hljs-string">'doSomething'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">($self, $params, $chain)</span> <span class="hljs-title">use</span> <span class="hljs-params">($log)</span> </span>{
    $log-&gt;info($params[<span class="hljs-string">'message'</span>];
    $chain-&gt;next($self, $params, $chain);
});
<span class="hljs-comment">// VS:</span>
SomeClass::signals()-&gt;connect(<span class="hljs-string">'doSomething'</span>, $log, <span class="hljs-string">'info'</span>);
</code></pre>
<p>Related to this, I personally dislike aggregating the filter parameters into a
single associative array. I don't like having to test for the existence of
parameters, and would much rather PHP tell me if I'm missing required
parameters or if any fail typehints. That said, doing so provides a consistent
API when filtering.</p>
</li>
</ul>
<p>All in all, however, the approach Lithium provides is very good; it just doesn't
completely suit my tastes or use cases.</p>
<h2>Signal Slots</h2>
<p>Interestingly, the capabilities I need are not far from what Lithium provides —
in fact, I'd argue that the Intercepting Filters of Lithium are actually
probably more akin to another pattern, <a href="http://en.wikipedia.org/wiki/Signals_and_slots">Signal Slots</a>.</p>
<p>With Signal Slots, your code emits <em>signals</em> (Lithium does this — it emits the
name of the method being called); any handler, or <em>slot</em> (<em>filters</em> in Lithium),
connected to the signal is then executed.</p>
<p>As such, you typically have some sort of signal &quot;manager&quot; object (the <code>Filters</code>
class in Lithium) that aggregates signals and attached slots; this manager is
then composed into the object emitting signals. For those of you familiar with
events in JavaScript or other event-driven languages, this should sound quite
familiar.</p>
<p>Such an approach looks like this:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $signals;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signals</span><span class="hljs-params">(SignalSlot $signals = null)</span>
    </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">null</span> === $signals) {
            <span class="hljs-comment">// No argument? make sure we have a signal manager</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">null</span> === <span class="hljs-keyword">$this</span>-&gt;signals) {
                <span class="hljs-keyword">$this</span>-&gt;signals = <span class="hljs-keyword">new</span> Signals(); <span class="hljs-comment">// SignalSlot implementation</span>
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Compose in an instance of a signal manager</span>
            <span class="hljs-keyword">$this</span>-&gt;signals = $signals;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;signals;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span><span class="hljs-params">($with, $these, $args)</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;signals()-&gt;emit(<span class="hljs-string">'doSomething.pre'</span>, <span class="hljs-keyword">$this</span>, $with, $these, $args);
        
        <span class="hljs-comment">// do some work</span>
        <span class="hljs-keyword">$this</span>-&gt;signals()-&gt;emit(<span class="hljs-string">'doSomething.during'</span>, <span class="hljs-keyword">$this</span>, $with, $these, $args);

        <span class="hljs-comment">// do some more work</span>
        <span class="hljs-comment">// This time, pass the result</span>
        <span class="hljs-keyword">$this</span>-&gt;signals()-&gt;emit(<span class="hljs-string">'doSomething.post'</span>, <span class="hljs-keyword">$this</span>, $result, $with, $these, $args);
        <span class="hljs-keyword">return</span> $result;
    }
}

$f = <span class="hljs-keyword">new</span> Foo();
$f-&gt;signals()-&gt;connect(<span class="hljs-string">'doSomething.pre'</span>, $log, <span class="hljs-string">'info'</span>);
$f-&gt;signals()-&gt;connect(<span class="hljs-string">'doSomething.during'</span>, $validator, <span class="hljs-string">'isValid'</span>);
$f-&gt;signals()-&gt;connect(<span class="hljs-string">'doSomething.post'</span>, $indexer, <span class="hljs-string">'index'</span>);
</code></pre>
<p>Basically, a <code>SignalSlot</code> provides an object in which signals and their attached
slots are aggregated. This allows having a single manager for multiple signals
(which is similar to how Lithium's <code>Filters</code> class works), while also providing
a way to emit multiple signals from a single procedure. Additionally, since it
is simply an object, you can compose it in to classes that may emit signals —
without requiring inheritance.</p>
<p>This is the basic approach of the <a href="https://github.com/zendframework/zf2/tree/master/library/Zend/SignalSlot">ZF2 SignalSlot implementation</a>,
as well as that found in <a href="http://components.symfony-project.org/event-dispatcher/">Symfony 2's Event Dispatcher</a>
and <a href="http://incubator.apache.org/zetacomponents/documentation/trunk/SignalSlot/tutorial.html">Zeta Components' SignalSlot component</a>.</p>
<p>Both Symfony 2's Event Dispatcher and ZF2's <code>SignalSlot</code> component build in the
ability to short-circuit, Symfony via a <code>notifyUntil()</code> method, and ZF2 via an
<code>emitUntil</code> method. With ZF2, each time a signal is emitted, a
<code>ResponseCollection</code> is returned by the manager, containing an aggregate of all
slot responses. Calling <code>emitUntil()</code> will short-circuit execution of remaining
slots if a given slot returns a response that validates against given criteria;
at this point, the collection is marked as &quot;stopped&quot;, and you can pull the
&quot;last&quot; response and return it:</p>
<pre><code class="language-php hljs php" data-lang="php">$responses = <span class="hljs-keyword">$this</span>-&gt;signals()-&gt;emitUntil(<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($response)</span> </span>{
    <span class="hljs-keyword">return</span> ($response <span class="hljs-keyword">instanceof</span> SpecificResultType);
}, <span class="hljs-string">'doSomething.pre'</span>, <span class="hljs-keyword">$this</span>, $with, $these, $args);
<span class="hljs-keyword">if</span> ($responses-&gt;stopped()) {
    <span class="hljs-keyword">return</span> $responses-&gt;last();
}
</code></pre>
<p>This introduces extra code in the method emitting the signals — but meets the
criteria that no given slot need be aware of the chain.</p>
<p>The Signal Slot approach actually supports paradigms similar to those
illustrated in Lithium. For instance, I can make my method body a slot:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $handlers = <span class="hljs-keyword">array</span>();

    <span class="hljs-comment">// ... skip signals composition ...</span>
    
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span><span class="hljs-params">($with, $these, $args)</span>
    </span>{
        $params = compact(<span class="hljs-string">'with'</span>, <span class="hljs-string">'these'</span>, <span class="hljs-string">'args'</span>);
        
        <span class="hljs-comment">// connect() returns a signal handler (slot); store it so that we only</span>
        <span class="hljs-comment">// ever attach it once...</span>
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>(<span class="hljs-keyword">$this</span>-&gt;handlers[<span class="hljs-keyword">__FUNCTION__</span>])) {
            <span class="hljs-keyword">$this</span>-&gt;handlers[<span class="hljs-keyword">__FUNCTION__</span>] = <span class="hljs-keyword">$this</span>-&gt;signals()-&gt;connect(<span class="hljs-keyword">__FUNCTION__</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($self, $params)</span> </span>{
                <span class="hljs-comment">// do the work here!</span>
            });
        }
        
        <span class="hljs-comment">// Emit the signal, and return the last result</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;signals()-&gt;emit(<span class="hljs-keyword">__FUNCTION__</span>, <span class="hljs-keyword">$this</span>, $params)-&gt;last();
    }
}
</code></pre>
<h2>Concerns</h2>
<p>Using Signal Slots and Intercepting Filters is not without its concerns, nor is
any given implementation perfect.</p>
<ul>
<li>Zeta Components does a fantastic job of handling signal slots. However, you
cannot short-circuit execution, nor introspect return values. It does offer
two features neither ZF2 nor Symfony 2 offer (at this time): the ability to
<em>statically</em> connect slots to signals, allowing you to wire without having an
existing instance, nor even caring what object might emit the signal; and the
ability to add a priority to slots, which allows you to alter the execution
order.</li>
<li>Lithium does a nice job of providing good standards (signals are method names;
parameters are predictable for all handlers), but at the price of some
flexibility (static implementation with no interface for alternate
implementations; no ability to re-use existing methods and functions with
differing signatures without currying).</li>
<li>Symfony 2 offers short-ciruiting and flexibility in callbacks, but requires
that you create an event object to pass to the Event Dispatcher, making the
usage slightly more verbose, and offers no standardization of signal naming.</li>
<li>ZF2's <code>SignalSlots</code> offer similar benefits (and drawbacks) to Symfony 2's
implementation, provides standardization of the signal manager response,
allows registering classes that self-register with the signal handler, but
lacks static wiring capabilities or prioritization.</li>
</ul>
<p>On a more abstract level, signal slots and intercepting filters can lead to
difficulties in learning and mastering code that use them:</p>
<p>How are signals named?</p>
<p>How do you document the parameters available to slots/filters?</p>
<ul>
<li>How can those using IDEs discover available signals? and the arguments expected?</li>
</ul>
<p>Where does the wiring occur?</p>
<ul>
<li>For instance, if any wiring is automated, this can potentially lead to more difficulty in debugging.</li>
<li>If done manually, when, and where?</li>
</ul>
<p>What happens if a slot doesn't receive arguments it needs, or cannot handle the arguments it receives?</p>
<p>In short, while they solve many problems, the implementations also introduce new
concerns — though this will be true of any extension system, in my experience.</p>
<h2>Conclusions</h2>
<p>I personally am a huge fan of Intercepting Filters and Signal Slots. I think
they can make code easier to extend, by providing a standard methodology for
introducing cross-cutting concerns without requiring class extension. They can
also make code quite expressive — sometimes at the cost of readability — by
introducing functional programming paradigms.</p>
<p>If you have not investigated these concepts or components before, I highly
recommend doing so; I think they play a fundamental role in the next generation
of PHP frameworks.</p>
<h2>Caveats</h2>
<p>I am not an expert, nor well-versed, in all the frameworks listed here, and as
such, some of the information may be incorrect or incomplete. I am the author of
ZF2's current Signal Slot implementation, and am still working on improvements
to it.</p>
<h2>Updates</h2>
<ul>
<li><strong>2011-01-10 11:35Z-05:00</strong> Cal Evans found the original php|architect article
I referenced, and I've revised some of the assessments based on re-reading it,
as well as linked to the issue.</li>
</ul>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/251-aspects-filters-and-signals-oh-my.html">Aspects, Filters, and Signals, Oh, My!</a> was originally
    published <time class="dt-published" datetime="2011-01-10T09:30:00-06:00">10 January 2011</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Symfony Live 2010</title>
      <pubDate>Sun, 21 Feb 2010 18:53:00 -0600</pubDate>
      <link>https://mwop.net/blog/232-Symfony-Live-2010.html</link>
      <guid>https://mwop.net/blog/232-Symfony-Live-2010.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>This week, I've been attending <a href="http://www.symfony-live.com/">Symfony Live</a> in
Paris, speaking on integrating Zend Framework with Symfony. The experience has
been quite rewarding, and certainly eye-opening for many.</p>
<p>To be honest, I was a little worried about the conference — many see Symfony and
ZF as being in competition, and that there would be no cross-pollination. I'm
hoping that between <a href="http://fabien.potencier.org/">Fabien</a>,
<a href="http://www.leftontheweb.com/">Stefan</a>, and myself, we helped dispel that myth
this week.</p>


<p>The fact of the matter is that no single project can be fully comprehensive, and
do everything perfectly. In my examinations of different frameworks, PHP and
otherwise, the places where they most differ and which generates the most
loyalty amongst users are the MVC approaches and tooling support. In good
frameworks, this is just a portion of the code, and the remainder is in support
libraries or plugins that extend that functionality.</p>
<p>This is true of both Symfony and Zend Framework. Symfony's development team has
chosen to focus on a very specific core of functionality related to the MVC
approach, which makes their maintenance job easier, and leads to a stable
product. Zend Framework's MVC implementation is offered as a group of separate
components, with components such as <code>Zend_Application</code> and <code>Zend_Tool</code> helping
to bring cohesion and structure to them.</p>
<p>What this means is that once you've developed the basic infrastructure of your
application, the scaffolding, you're now left with decisions about how to
implement the actual functionality of the application itself. The problem as I
see it is: how do you do that development? Many developers are myopic and will
not look beyond the framework they have chosen for for development. This can
lead to multiple implementations of the same code, and often leads to incomplete
implementations as well.</p>
<p>My feeling is that whenever you find yourself about to write new code, look to
see if somebody else has written the code already. Anybody — don't limit
yourself to your framework of choice. If I want to do serious HTML sniffing,
validation, and cleanup, I go to <a href="http://htmlpurifier.org/">HTMLPurifier</a>; if I
want a workflow component, I check out <a href="http://www.ezcomponents.org/docs/api/latest/introduction_Workflow.html">eZ Components Workflow</a>;
I always check <a href="http://pear.php.net/">PEAR</a>.</p>
<p>This week, I tried to spread this message within the
<a href="http://symfony-project.org">Symfony</a> community, showing them how easy it is to
integrate ZF components within Symfony projects. The integration itself is
simple: instantiate the Zend autoloader, and start using ZF classes. This same
technique can be used to load PEAR, or eZComponents, or Doctrine 2, etc. The
trick is getting out of the &quot;Not Invented Here&quot; syndrome, letting go of your
ego, and using <em>other</em> people's code.</p>
<p>(Yes, I know we have code in ZF duplicating functionality in other libraries; in
most cases, we try and offer at least a new approach to the problem — but we
could do better.)</p>
<p>Fabien also made an interesting announcement. During a Q&amp;A session with the
Symfony core team, he said that Symfony 2 will not write re-invent the wheel
when it doesn't need to — and announced that Symfony 2 will be using <code>Zend_Log</code>
and <code>Zend_Cache</code> instead of rewriting the current Symfony components. I find
this admirable — and it's something I'm hoping to do in a few places with Zend
Framework 2.0 as well, as I know there are features and code that others have,
quite simply, written better.</p>
<p>One last note in this ramble: With the various &quot;2.0&quot; versions of frameworks,
most projects are learning from both mistakes made as well as from the usage
patters of the developers adopting them. One of those lessons, to my mind, is
that no one framework can do it all well and by themselves. I fully expect to
see the next generation of frameworks making it trivial to pull features from
other frameworks and libraries in order to fill out functionality.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/232-Symfony-Live-2010.html">Symfony Live 2010</a> was originally
    published <time class="dt-published" datetime="2010-02-17T11:39:43-06:00">17 February 2010</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
