<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Blog entries tagged symfony :: mwop.net</title>
  <updated>2011-01-14T08:53:52-06:00</updated>
  <generator uri="https://getlaminas.org" version="2">Laminas_Feed_Writer</generator>
  <link rel="alternate" type="text/html" href="https://mwop.net/blog/tag/symfony"/>
  <link rel="self" type="application/atom+xml" href="https://mwop.net/blog/tag/symfony/atom.xml"/>
  <id>https://mwop.net/blog/tag/symfony</id>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Aspects, Filters, and Signals, Oh, My!]]></title>
    <published>2011-01-10T09:30:00-06:00</published>
    <updated>2011-01-14T08:53:52-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/251-aspects-filters-and-signals-oh-my.html"/>
    <id>https://mwop.net/blog/251-aspects-filters-and-signals-oh-my.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>Last month, during <xhtml:a href="http://phpadvent.org">PHP
Advent</xhtml:a>, <xhtml:a href="http://ohloh.net/accounts/gwoo">gwoo</xhtml:a> wrote
an interesting post on <xhtml:a href="http://phpadvent.org/2010/aspect-oriented-design-by-garrett-woodworth">
Aspect-Oriented Design</xhtml: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.</xhtml:p>
<xhtml:p>But first, some background is probably in order, as this is a
jargon-heavy post.</xhtml:p>
<xhtml:h2>Aspect Oriented Programming</xhtml:h2>
<xhtml:p>I was first introduced to AOP in 2006 via an <xhtml:a href="http://www.phparch.com/magazine/2006-2/april/">April 2006
php|architect article by Dmitry Sheiko</xhtml: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:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">interface</xhtml:span> <xhtml:span class="hljs-title">Listener</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">notify</xhtml:span><xhtml:span class="hljs-params">($signal, $argv = null)</xhtml:span></xhtml:span>;
}

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

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

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">doSomething</xhtml:span><xhtml:span class="hljs-params">($arg1, $arg2)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">foreach</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;listeners <xhtml:span class="hljs-keyword">as</xhtml:span> $listener) {
            $listener-&gt;notify(<xhtml:span class="hljs-string">'preDoSomething'</xhtml:span>, func_get_args());
        }
        
        <xhtml:span class="hljs-comment">// do some work</xhtml:span>
        
        <xhtml:span class="hljs-keyword">foreach</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;listeners <xhtml:span class="hljs-keyword">as</xhtml:span> $listener) {
            $listener-&gt;notify(<xhtml:span class="hljs-string">'postDoSomething'</xhtml:span>, $result);
        }
    }
}
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:h2>Intercepting Filters</xhtml:h2>
<xhtml:p>A similar concept to AOP is the idea of <xhtml:a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html">
Intercepting</xhtml:a> <xhtml:a href="http://msdn.microsoft.com/en-us/library/ff647251.aspx">Filters</xhtml: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.</xhtml:p>
<xhtml:p><xhtml:a href="http://lithify.me/">Lithium</xhtml: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:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">Dispatcher::applyFilter(<xhtml:span class="hljs-string">'run'</xhtml:span>, <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-params">($self, $params, $chain)</xhtml:span> </xhtml:span>{
    <xhtml:span class="hljs-comment">// do something...</xhtml:span>
    <xhtml:span class="hljs-keyword">return</xhtml:span> $chain-&gt;next($self, $params, $chain);
});
</xhtml:code></xhtml:pre>
<xhtml: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 <xhtml:code>next()</xhtml: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.</xhtml:p>
<xhtml:p>The above example defines a filter that will run when the
<xhtml:code>run()</xhtml:code> method of the <xhtml:code>Dispatcher</xhtml:code> class is
executed. <xhtml:code>$self</xhtml:code> will typically be the object instance,
<xhtml:code>$params</xhtml:code> an array of the parameters passed to the
method, and <xhtml:code>$chain</xhtml:code> as described above. The method
itself will execute any filters — typically with something like
this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">lithium</xhtml:span>/<xhtml:span class="hljs-title">core</xhtml:span>/<xhtml:span class="hljs-title">Object</xhtml:span> <xhtml:span class="hljs-title">as</xhtml:span> <xhtml:span class="hljs-title">BaseObject</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Foo</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">BaseObject</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">doSomething</xhtml:span><xhtml:span class="hljs-params">($with, $these, $args)</xhtml:span>
    </xhtml:span>{
        $params = compact(<xhtml:span class="hljs-string">'with'</xhtml:span>, <xhtml:span class="hljs-string">'these'</xhtml:span>, <xhtml:span class="hljs-string">'args'</xhtml:span>);
        
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_filter(<xhtml:span class="hljs-keyword">__METHOD__</xhtml:span>, $params, <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-params">($self, $params)</xhtml:span> </xhtml:span>{
            <xhtml:span class="hljs-comment">// do the actual work here</xhtml:span>
            <xhtml:span class="hljs-keyword">return</xhtml:span> $result;
        });
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>(The <xhtml:code>_filter()</xhtml:code> method is defined in
<xhtml:code>lithium\core\Object</xhtml:code>, and basically passes a local,
static chain of filters to Lithium's <xhtml:code>Filter</xhtml:code> class for
execution. <xhtml:code>applyFilter()</xhtml:code> from the previous example
statically adds a callback under the named method to the
chain.)</xhtml:p>
<xhtml:p>This solution is elegant — but I see some limitations:</xhtml:p>
<xhtml:ul>
<xhtml:li>
<xhtml: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 <xhtml:em>consuming</xhtml: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).</xhtml:p>
<xhtml:p>Additionally, the easiest way to implement filtering in Lithium
is by extending the <xhtml:code>lithium\core\Object</xhtml:code> class — I
could find no examples elsewhere in the documentation that showed
how you would compose the <xhtml:code>Filters</xhtml: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.</xhtml:p>
</xhtml:li>
<xhtml:li>
<xhtml: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.)</xhtml:p>
</xhtml:li>
<xhtml:li>
<xhtml:p>Third, it's sometimes useful to have access to the return
results of <xhtml:em>all</xhtml: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.</xhtml:p>
</xhtml:li>
<xhtml:li>
<xhtml: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:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">Filters::add(<xhtml:span class="hljs-string">'SomeClass::doSomething'</xhtml:span>, <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-params">($method, $self, $params)</xhtml:span> </xhtml:span>{
    <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">null</xhtml:span> !== ($content = cache_hit($params))) {
        <xhtml:span class="hljs-keyword">return</xhtml:span> $content;
    }
    $content = Filters::next($method, $self, $params);
    <xhtml:span class="hljs-keyword">return</xhtml:span> $content;
});
</xhtml:code></xhtml:pre>
<xhtml:p>However, if you have several filters such as this, the order
then becomes paramount, and that introduces new complexities.</xhtml:p>
<xhtml:p>Another example would be with façade methods, where you may wish
to introduce filters before and after each method call:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">doSomeWorkflow</xhtml:span><xhtml:span class="hljs-params">($message)</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;somePrivateMethod($message);
    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;nextPrivateMethod($message);
    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;lastPrivateMethod($message);
}
</xhtml:code></xhtml:pre>
<xhtml:p>(I can already hear <xhtml:a href="http://nateabele.com/">Nate</xhtml:a>
saying "make those all filters!" or "filter each method!" — but
that's the problem with simple examples - they can't always express
the nuances of a use case.)</xhtml:p>
</xhtml:li>
<xhtml:li>
<xhtml: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 <xhtml:a href="http://en.wikipedia.org/wiki/Currying">curry</xhtml:a> the calls in,
instead of simply using the existing method:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-comment">// This:</xhtml:span>
SomeClass::applyFilter(<xhtml:span class="hljs-string">'doSomething'</xhtml:span>, <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-params">($self, $params, $chain)</xhtml:span> <xhtml:span class="hljs-title">use</xhtml:span> <xhtml:span class="hljs-params">($log)</xhtml:span> </xhtml:span>{
    $log-&gt;info($params[<xhtml:span class="hljs-string">'message'</xhtml:span>];
    $chain-&gt;next($self, $params, $chain);
});
<xhtml:span class="hljs-comment">// VS:</xhtml:span>
SomeClass::signals()-&gt;connect(<xhtml:span class="hljs-string">'doSomething'</xhtml:span>, $log, <xhtml:span class="hljs-string">'info'</xhtml:span>);
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
</xhtml:li>
</xhtml:ul>
<xhtml:p>All in all, however, the approach Lithium provides is very good;
it just doesn't completely suit my tastes or use cases.</xhtml:p>
<xhtml:h2>Signal Slots</xhtml:h2>
<xhtml: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,
<xhtml:a href="http://en.wikipedia.org/wiki/Signals_and_slots">Signal
Slots</xhtml:a>.</xhtml:p>
<xhtml:p>With Signal Slots, your code emits <xhtml:em>signals</xhtml:em> (Lithium
does this — it emits the name of the method being called); any
handler, or <xhtml:em>slot</xhtml:em> (<xhtml:em>filters</xhtml:em> in Lithium), connected
to the signal is then executed.</xhtml:p>
<xhtml:p>As such, you typically have some sort of signal "manager" object
(the <xhtml:code>Filters</xhtml: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.</xhtml:p>
<xhtml:p>Such an approach looks like this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Foo</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $signals;

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

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

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

$f = <xhtml:span class="hljs-keyword">new</xhtml:span> Foo();
$f-&gt;signals()-&gt;connect(<xhtml:span class="hljs-string">'doSomething.pre'</xhtml:span>, $log, <xhtml:span class="hljs-string">'info'</xhtml:span>);
$f-&gt;signals()-&gt;connect(<xhtml:span class="hljs-string">'doSomething.during'</xhtml:span>, $validator, <xhtml:span class="hljs-string">'isValid'</xhtml:span>);
$f-&gt;signals()-&gt;connect(<xhtml:span class="hljs-string">'doSomething.post'</xhtml:span>, $indexer, <xhtml:span class="hljs-string">'index'</xhtml:span>);
</xhtml:code></xhtml:pre>
<xhtml:p>Basically, a <xhtml:code>SignalSlot</xhtml: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 <xhtml:code>Filters</xhtml: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.</xhtml:p>
<xhtml:p>This is the basic approach of the <xhtml:a href="https://github.com/zendframework/zf2/tree/master/library/Zend/SignalSlot">
ZF2 SignalSlot implementation</xhtml:a>, as well as that found in
<xhtml:a href="http://components.symfony-project.org/event-dispatcher/">Symfony
2's Event Dispatcher</xhtml:a> and <xhtml:a href="http://incubator.apache.org/zetacomponents/documentation/trunk/SignalSlot/tutorial.html">
Zeta Components' SignalSlot component</xhtml:a>.</xhtml:p>
<xhtml:p>Both Symfony 2's Event Dispatcher and ZF2's
<xhtml:code>SignalSlot</xhtml:code> component build in the ability to
short-circuit, Symfony via a <xhtml:code>notifyUntil()</xhtml:code> method, and
ZF2 via an <xhtml:code>emitUntil</xhtml:code> method. With ZF2, each time a
signal is emitted, a <xhtml:code>ResponseCollection</xhtml:code> is returned by
the manager, containing an aggregate of all slot responses. Calling
<xhtml:code>emitUntil()</xhtml: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
"stopped", and you can pull the "last" response and return it:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">$responses = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;signals()-&gt;emitUntil(<xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span><xhtml:span class="hljs-params">($response)</xhtml:span> </xhtml:span>{
    <xhtml:span class="hljs-keyword">return</xhtml:span> ($response <xhtml:span class="hljs-keyword">instanceof</xhtml:span> SpecificResultType);
}, <xhtml:span class="hljs-string">'doSomething.pre'</xhtml:span>, <xhtml:span class="hljs-keyword">$this</xhtml:span>, $with, $these, $args);
<xhtml:span class="hljs-keyword">if</xhtml:span> ($responses-&gt;stopped()) {
    <xhtml:span class="hljs-keyword">return</xhtml:span> $responses-&gt;last();
}
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:p>The Signal Slot approach actually supports paradigms similar to
those illustrated in Lithium. For instance, I can make my method
body a slot:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Foo</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $handlers = <xhtml:span class="hljs-keyword">array</xhtml:span>();

    <xhtml:span class="hljs-comment">// ... skip signals composition ...</xhtml:span>
    
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">doSomething</xhtml:span><xhtml:span class="hljs-params">($with, $these, $args)</xhtml:span>
    </xhtml:span>{
        $params = compact(<xhtml:span class="hljs-string">'with'</xhtml:span>, <xhtml:span class="hljs-string">'these'</xhtml:span>, <xhtml:span class="hljs-string">'args'</xhtml:span>);
        
        <xhtml:span class="hljs-comment">// connect() returns a signal handler (slot); store it so that we only</xhtml:span>
        <xhtml:span class="hljs-comment">// ever attach it once...</xhtml:span>
        <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">isset</xhtml:span>(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;handlers[<xhtml:span class="hljs-keyword">__FUNCTION__</xhtml:span>])) {
            <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;handlers[<xhtml:span class="hljs-keyword">__FUNCTION__</xhtml:span>] = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;signals()-&gt;connect(<xhtml:span class="hljs-keyword">__FUNCTION__</xhtml:span>, <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span><xhtml:span class="hljs-params">($self, $params)</xhtml:span> </xhtml:span>{
                <xhtml:span class="hljs-comment">// do the work here!</xhtml:span>
            });
        }
        
        <xhtml:span class="hljs-comment">// Emit the signal, and return the last result</xhtml:span>
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;signals()-&gt;emit(<xhtml:span class="hljs-keyword">__FUNCTION__</xhtml:span>, <xhtml:span class="hljs-keyword">$this</xhtml:span>, $params)-&gt;last();
    }
}
</xhtml:code></xhtml:pre>
<xhtml:h2>Concerns</xhtml:h2>
<xhtml:p>Using Signal Slots and Intercepting Filters is not without its
concerns, nor is any given implementation perfect.</xhtml:p>
<xhtml:ul>
<xhtml: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 <xhtml:em>statically</xhtml: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.</xhtml:li>
<xhtml: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).</xhtml:li>
<xhtml: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.</xhtml:li>
<xhtml:li>ZF2's <xhtml:code>SignalSlots</xhtml: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.</xhtml:li>
</xhtml:ul>
<xhtml:p>On a more abstract level, signal slots and intercepting filters
can lead to difficulties in learning and mastering code that use
them:</xhtml:p>
<xhtml:p>How are signals named?</xhtml:p>
<xhtml:p>How do you document the parameters available to
slots/filters?</xhtml:p>
<xhtml:ul>
<xhtml:li>How can those using IDEs discover available signals? and the
arguments expected?</xhtml:li>
</xhtml:ul>
<xhtml:p>Where does the wiring occur?</xhtml:p>
<xhtml:ul>
<xhtml:li>For instance, if any wiring is automated, this can potentially
lead to more difficulty in debugging.</xhtml:li>
<xhtml:li>If done manually, when, and where?</xhtml:li>
</xhtml:ul>
<xhtml:p>What happens if a slot doesn't receive arguments it needs, or
cannot handle the arguments it receives?</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:h2>Conclusions</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:h2>Caveats</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml:h2>Updates</xhtml:h2>
<xhtml:ul>
<xhtml:li><xhtml:strong>2011-01-10 11:35Z-05:00</xhtml: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.</xhtml:li>
</xhtml:ul>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml: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!</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2011-01-10T09:30:00-06:00">10
January 2011</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Symfony Live 2010]]></title>
    <published>2010-02-17T11:39:43-06:00</published>
    <updated>2010-02-21T18:53:00-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/232-Symfony-Live-2010.html"/>
    <id>https://mwop.net/blog/232-Symfony-Live-2010.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>This week, I've been attending <xhtml:a href="http://www.symfony-live.com/">Symfony Live</xhtml:a> in Paris, speaking
on integrating Zend Framework with Symfony. The experience has been
quite rewarding, and certainly eye-opening for many.</xhtml:p>
<xhtml: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 <xhtml:a href="http://fabien.potencier.org/">Fabien</xhtml:a>, <xhtml:a href="http://www.leftontheweb.com/">Stefan</xhtml:a>, and myself, we helped
dispel that myth this week.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml: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 <xhtml:code>Zend_Application</xhtml:code>
and <xhtml:code>Zend_Tool</xhtml:code> helping to bring cohesion and structure
to them.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml: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
<xhtml:a href="http://htmlpurifier.org/">HTMLPurifier</xhtml:a>; if I want a
workflow component, I check out <xhtml:a href="http://www.ezcomponents.org/docs/api/latest/introduction_Workflow.html">
eZ Components Workflow</xhtml:a>; I always check <xhtml:a href="http://pear.php.net/">PEAR</xhtml:a>.</xhtml:p>
<xhtml:p>This week, I tried to spread this message within the <xhtml:a href="http://symfony-project.org">Symfony</xhtml: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 "Not Invented Here" syndrome, letting go of your ego, and
using <xhtml:em>other</xhtml:em> people's code.</xhtml:p>
<xhtml: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.)</xhtml:p>
<xhtml: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 <xhtml:code>Zend_Log</xhtml:code> and
<xhtml:code>Zend_Cache</xhtml: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.</xhtml:p>
<xhtml:p>One last note in this ramble: With the various "2.0" 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.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/232-Symfony-Live-2010.html">Symfony Live
2010</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2010-02-17T11:39:43-06:00">17 February 2010</xhtml:time> on
<xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
</feed>
