<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Notes Log</title>
	<atom:link href="http://noteslog.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://noteslog.com</link>
	<description></description>
	<lastBuildDate>Sat, 15 May 2010 13:31:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>What&#8217;s the market value of a resume?</title>
		<link>http://noteslog.com/post/whats-the-market-value-of-a-resume/</link>
		<comments>http://noteslog.com/post/whats-the-market-value-of-a-resume/#comments</comments>
		<pubDate>Sat, 15 May 2010 13:31:55 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=704</guid>
		<description><![CDATA[I&#8217;m sure there is value in a resume, and it&#8217;s a market value. I just don&#8217;t get the details, but I&#8217;m pretty sure of it. Companies collect resumes for employing people for many different purposes (to work inside, to send them to another company to work there, to send them to another company to work in yet [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m sure there is value in a resume, and it&#8217;s a market value.<br />
I just don&#8217;t get the details, but I&#8217;m pretty sure of it.</p>
<p>Companies collect resumes for employing people for many different purposes (to work inside, to send them to another company to work there, to send them to another company to work in yet another company, to work in another company, &#8230;)</p>
<p>Job search engines are big collectors of resumes. Usually they are the key that opens the door to their offerings.</p>
<p>Resumes are sold and bought, they&#8217;re not open souce, but authors provide them for free!!</p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/whats-the-market-value-of-a-resume/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Centrodestra e centrosinistra</title>
		<link>http://noteslog.com/post/centrodestra-e-centrosinistra/</link>
		<comments>http://noteslog.com/post/centrodestra-e-centrosinistra/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 21:57:42 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=686</guid>
		<description><![CDATA[Sto leggendo il Corriere della Sera, edizione Internet. Inciampo continuamente sulle parole centrodestra e centrosinistra: non sarebbe più semplice dire solo destra e sinistra? L&#8217;eredità del centro dopo la cancellazione della Democrazia Cristiana, perdura nelle espressioni centrodestra e centrosinistra. Mitigando la paura della destra nei confronti della sinistra e viceversa, diamo al centro la stessa [...]]]></description>
			<content:encoded><![CDATA[<p>Sto leggendo il Corriere della Sera, edizione Internet.</p>
<p>Inciampo continuamente sulle parole centrodestra e centrosinistra: non sarebbe più semplice dire solo destra e sinistra?</p>
<p>L&#8217;eredità del centro dopo la cancellazione della Democrazia Cristiana, perdura nelle espressioni centrodestra e centrosinistra. Mitigando la paura della destra nei confronti della sinistra e viceversa, diamo al centro la stessa considerazione che permise alla DC governare indisturbata durante il dopoguerra. Parlando di centrodestra e centrosinistra rivendichiamo continuamente l&#8217;ineluttabilità del centro, e della mediocrità.</p>
<p>Chiamiamo le cose col loro nome, senza paura.</p>
<p>Destra e sinistra sono ormai contenitori di valori assai diversi da quelli di trent&#8217;anni fa, fascismo e comunismo sono morti e solo persistono nella nostra memoria, ma spero che non diventino tabù.</p>
<p>Grazie alla globalizzazione abbiamo sviluppato il pensiero unico, e la destra e la sinistra condividono adesso molti valori, tanto che i partiti politici italiani nati dopo Mani Pulite, non stanno nè a destra nè a sinistra.</p>
<p>Io vorrei che non stessero più nemmeno al centro.</p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/centrodestra-e-centrosinistra/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Chili NEXT on github</title>
		<link>http://noteslog.com/post/chili-next-on-github/</link>
		<comments>http://noteslog.com/post/chili-next-on-github/#comments</comments>
		<pubDate>Sun, 17 Jan 2010 20:40:34 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[Chili]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=673</guid>
		<description><![CDATA[I&#8217;ve setup a github account for Chili, based on the github account for jQuery. Anyone interested in forging the NEXT version of Chili is warmly welcome. You should be able to join and contribute as easily as possible. I&#8217;m still a bit new to git and github, but I hope I have prepared a usable setup for [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve setup a <a href="http://github.com/aercolino/Chili" target="_blank">github account for Chili</a>, based on the <a href="http://github.com/jquery/jquery" target="_blank">github account for jQuery</a>.</p>
<p>Anyone interested in forging the NEXT version of Chili is warmly welcome.</p>
<p>You should be able to join and contribute as easily as possible.</p>
<p>I&#8217;m still a bit new to git and github, but I hope I have prepared a usable setup for development.</p>
<p>The current source, is almost version 2.2, but heavily refactored, simplified and documented.</p>
<p>There are some minor differences, so that it&#8217;s not compatible with version 2.2 anymore.</p>
<p>NEXT version could be 2.3 or 3.0, most likely the latter.</p>
<p>In the github wiki I jotted down a minimal wish list.</p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/chili-next-on-github/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vital Bugs</title>
		<link>http://noteslog.com/post/vital-bugs/</link>
		<comments>http://noteslog.com/post/vital-bugs/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 21:32:42 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=667</guid>
		<description><![CDATA[Bugs feed me. Programmers hunt bugs for a living. Bugs feed programs. A program that is being debugged now, is alive. Bugs feed philosophy. Thinking is about confrontation with bugs in thoughts.]]></description>
			<content:encoded><![CDATA[<h4>Bugs feed me.</h4>
<p>Programmers hunt bugs for a living.</p>
<h4>Bugs feed programs.</h4>
<p>A program that is being debugged now, is alive.</p>
<h4>Bugs feed philosophy.</h4>
<p>Thinking is about confrontation with bugs in thoughts.</p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/vital-bugs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I18n gone crazy</title>
		<link>http://noteslog.com/post/i18n-gone-crazy/</link>
		<comments>http://noteslog.com/post/i18n-gone-crazy/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 19:22:29 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=665</guid>
		<description><![CDATA[Some time ago I stumbled upon this great message from some program on my PC, I can&#8217;t remember which one now. Haga doble clic en el icono de adv. en la barra est. para ver este mens. en el fut.]]></description>
			<content:encoded><![CDATA[<p>Some time ago I stumbled upon this great message from some program on my PC, I can&#8217;t remember which one now.</p>
<blockquote><p>Haga doble clic en el icono de adv. en la barra est. para ver este mens. en el fut.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/i18n-gone-crazy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Yet Another EventManager Class in PHP (5.3)</title>
		<link>http://noteslog.com/post/yet-another-eventmanager-class-in-php-5-3/</link>
		<comments>http://noteslog.com/post/yet-another-eventmanager-class-in-php-5-3/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 07:18:28 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=633</guid>
		<description><![CDATA[This EventManager class is for PHP 5.3. It has got the same features as Yet Another EventManager Class in PHP (&#60;5.3): EventManager is a Singleton EventManager events are strings EventManager bind() can attach handlers to regular expressions EventManager event handler arguments are loosely structured EventManager event handler return value is loosely structured EventManager gathers, stores, [...]]]></description>
			<content:encoded><![CDATA[<p>This EventManager class is for PHP 5.3. It has got the same features as <a href="http://noteslog.com/post/yet-another-eventmanager-class-in-php" target="_self">Yet Another EventManager Class in PHP (&lt;5.3)</a>:</p>
<ol>
<li>EventManager is a Singleton</li>
<li>EventManager events are strings</li>
<li>EventManager bind() can attach handlers to regular expressions</li>
<li>EventManager event handler arguments are loosely structured</li>
<li>EventManager event handler return value is loosely structured</li>
<li>EventManager gathers, stores, and eventually returns all handlers results</li>
</ol>
<p>plus the following:</p>
<ol>
<li>EventManager belongs to the Ando\Core namespace</li>
<li>EventManager event handlers can be any PHP callable expression</li>
<li>EventManager bind() / unbind() work with Callable objects</li>
</ol>
<h5>EventManager belongs to the Ando\Core namespace</h5>
<p>As a namespace for my projects I chose Ando, which is short, and tells a bit about me (Andrea), and a bit about Miho, my wife, which once called me Andorea.</p>
<h5>EventManager event handlers can be any PHP callable expression</h5>
<p>Global functions, class methods, object methods, and anonymous functions are all supported.</p>
<h5>EventManager bind() / unbind() work with Callable objects</h5>
<p>Not only bind() accepts any callable expression, but also accepts and returns an object of the class Ando\Core\Callable. This way, for unbinding an event handler, the Callable object that bind() returns must be passed to unbind().</p>
<p>Callable objects are just a wrapper around callable expressions, that allows for a uniform access and storage.</p>
<p><pre><code class="php">namespace Ando\Core;

class Callable
{
    private $_callable = null;
    
    public function __construct( $callable )
    {
        if (! is_callable( $callable ))
        {
            throw new Exception('Expected a callable expression');
        }
        $this-&gt;_callable = $callable;
    }
    
    public function __invoke($args, &amp; $stack)
    {
        $result = call_user_func_array($this-&gt;_callable,
                array_merge($args, array(&amp; $stack)));
        return $result;
    }
}</code></pre></p>
<p>&#8212;</p>
<h5>How to use many EventManager singletons at once</h5>
<p><pre><code class="php">require_once 'event_manager.php';

class AnotherEventManager extends Ando\Core\EventManager {}
Ando\Core\Singleton::instance('AnotherEventManager');

function hello($event, $world)
{
    echo &quot;Hello $world !&lt;br&gt;&quot;;
}

EventManager()-&gt;bind('hello', 'hello');
//AnotherEventManager()-&gt;bind('hello', 'hello');

AnotherEventManager()-&gt;trigger('hello', 'Popeye');</code></pre></p>
<p>As is, the previous scripts outputs nothing, but uncommenting the commented line you get</p>
<pre>Hello Popeye !</pre>
<h5><strong>Action Wrapping</strong></h5>
<p><pre class="ln-1"><code class="php">class Foo
{
  public function foo()
  {
    //...
    EventManager()-&gt;trigger('action:one:before', 3);
    sleep(3); //an action you want to wrap
    EventManager()-&gt;trigger('action:one:after', null);
    //...
  }
}

class Bar
{
  public function bar()
  {
    //...
    EventManager()-&gt;trigger('action:two:before', 2);
    sleep(2); //another action you want to wrap
    EventManager()-&gt;trigger('action:two:after', null);
    //...
  }
}

class ActionTracerPlugin
{
    public function trace($event, $data)
    {
        if (preg_match('/^action:(.*)$/', $event, $matches))
        {
            $action = $matches[1];
            $time = date('Y-m-d H:i:s');
            $data = var_export($data, true);
            file_put_contents('trace.txt', &quot;$time: $action: $data\n&quot;, FILE_APPEND);
        }
    }
}



require_once 'event_manager.php';

$tracer = new ActionTracerPlugin();
EventManager()-&gt;bind('/:(before|after)$/', array($tracer, 'trace'));

$foo = new Foo();
$foo-&gt;foo();

$bar = new Bar();
$bar-&gt;bar();

$foo-&gt;foo();

echo '&lt;pre&gt;', file_get_contents('trace.txt'), '&lt;/pre&gt;';</code></pre></p>
<p>Trace</p>
<pre>2009-11-16 07:17:29: one:before: 3
2009-11-16 07:17:32: one:after: NULL
2009-11-16 07:17:32: one:before: 3
2009-11-16 07:17:35: one:after: NULL
2009-11-16 07:17:35: two:before: 2
2009-11-16 07:17:37: two:after: NULL
2009-11-16 07:17:37: two:before: 2
2009-11-16 07:17:39: two:after: NULL
2009-11-16 07:17:39: one:before: 3
2009-11-16 07:17:42: one:after: NULL</pre>
<h5><strong>Runtime Class Extension</strong></h5>
<p><pre class="ln-1"><code class="php">class Foo
{
    public function __call($method, $arguments)
    {
        action('__call:start', $method);
        
        $stack = EventManager()-&gt;trigger(__METHOD__, $this, $method, $arguments);
        if (! count($stack))
        {
            action('__call:exception');
            throw new Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
        }

        $last = array_pop($stack);
        $result = $last['result'];
        action('__call:end', $result);
        return $result;
    }
}

class Bar
{
    public function barMethodForFoo($event, $foo, $method, $arguments, $stack)
    {
        action('barMethodForFoo:start', $arguments);
        if (! ($foo instanceof Foo &amp;&amp; 'bar' == $method))
        {
            array_pop($stack);
            return;
        }
        action('barMethodForFoo:begin');
        
        $someValue = 'Hello ' . $arguments[0] . ' !';

        action('barMethodForFoo:end', $someValue);
        return $someValue;
    }
}

class Baz
{
    public function bazMethodForFoo($event, $foo, $method, $arguments, $stack)
    {
        action('bazMethodForFoo:start', $arguments);
        if (! ($foo instanceof Foo &amp;&amp; 'baz' == $method))
        {
            array_pop($stack);
            return;
        }
        action('bazMethodForFoo:begin');
        
        $someValue = 'I love ' . $arguments[0] . ' !';

        action('bazMethodForFoo:end', $someValue);
        return $someValue;
    }
}

class ActionTracerPlugin
{
    public function trace($event, $data)
    {
        if (preg_match('/^action:(.*)$/', $event, $matches))
        {
            $action = $matches[1];
            $time = date('Y-m-d H:i:s');
            $data = var_export($data, true);
            file_put_contents('trace.txt', &quot;$time: $action: $data\n&quot;, FILE_APPEND);
        }
    }
}

function action($action, $data = null)
{
    EventManager()-&gt;trigger(&quot;action:$action&quot;, $data);
}



require_once 'event_manager.php';

$tracer = new ActionTracerPlugin();
EventManager()-&gt;bind('/^action:/', array($tracer, 'trace'));

$foo = new Foo();
$bar = new Bar();
$baz = new Baz();

EventManager()-&gt;bind('Foo::__call', array($bar, 'barMethodForFoo'));

$foo-&gt;bar(&quot;Olivia&quot;);
    
try
{
    action('baz without bind:before');
    $foo-&gt;baz(&quot;spinach&quot;);
    action('baz without bind:after');
}
catch (Exception $e)
{
    EventManager()-&gt;bind('Foo::__call', array($baz, 'bazMethodForFoo'));
    
    action('baz with bind:before');
    $foo-&gt;baz(&quot;you&quot;);
    action('baz with bind:after');
}

echo '&lt;pre&gt;', file_get_contents('trace.txt'), '&lt;/pre&gt;';</code></pre></p>
<p>Trace</p>
<p><pre class="chili-all"><code>2009-11-16 07:14:54: __call:start: 'bar'
2009-11-16 07:14:54: barMethodForFoo:start: array (
  0 =&gt; 'Olivia',
)
2009-11-16 07:14:54: barMethodForFoo:begin: NULL
2009-11-16 07:14:54: barMethodForFoo:end: 'Hello Olivia !'
2009-11-16 07:14:54: __call:end: 'Hello Olivia !'
2009-11-16 07:14:54: baz without bind:before: NULL
2009-11-16 07:14:54: __call:start: 'baz'
2009-11-16 07:14:54: barMethodForFoo:start: array (
  0 =&gt; 'spinach',
)
2009-11-16 07:14:54: __call:exception: NULL
2009-11-16 07:14:54: baz with bind:before: NULL
2009-11-16 07:14:54: __call:start: 'baz'
2009-11-16 07:14:54: barMethodForFoo:start: array (
  0 =&gt; 'you',
)
2009-11-16 07:14:54: bazMethodForFoo:start: array (
  0 =&gt; 'you',
)
2009-11-16 07:14:54: bazMethodForFoo:begin: NULL
2009-11-16 07:14:54: bazMethodForFoo:end: 'I love you !'
2009-11-16 07:14:54: __call:end: 'I love you !'
2009-11-16 07:14:54: baz with bind:after: NULL</code></pre></p>
<h5><strong>Filters Pipeline</strong></h5>
<p><pre class="ln-1"><code class="php">class Foo
{
    public function show($someThing)
    {
        $stack = EventManager()-&gt;trigger('filter:show', $someThing);
        $result = array_pop($stack);
        echo $result['result'];
    }
}

class Bar
{
    static public function the_to_a($event, $someThing, $stack)
    {
        if (! preg_match('/^filter:/', $event))
        {
            return array_pop($stack);
        }
        $result = EventManager()-&gt;pipeline($someThing, $stack);
        $result = preg_replace('/\bthe\b/i', 'a', $result);
        return array('result' =&gt; $result, 'stopPropagation' =&gt; true);
    }
    
    public function markdown($event, $someThing, $stack)
    {
        if (! preg_match('/^filter:/', $event))
        {
            return array_pop($stack);
        }
        EventManager()-&gt;pipeline($someThing, $stack);
        $result = preg_replace('/_([^_]+)_/', '&lt;em&gt;\1&lt;/em&gt;', $result);
        $result = preg_replace('/\*([^*]+)\*/', '&lt;strong&gt;\1&lt;/strong&gt;', $result);
        return $result;
    }
}



require_once 'event_manager.php';

function upper4 ($event, $someThing, $stack)
{
    if (! preg_match('/^filter:/', $event))
    {
        return array_pop($stack);
    }
    $result = EventManager()-&gt;pipeline($someThing, $stack);
    $result = preg_replace('/\b(\w{4})\b/e', 'strtoupper(&quot;\1&quot;)', $result);
    return $result;
};
$upper4 = EventManager()-&gt;bind('filter:show', 'upper4');

EventManager()-&gt;bind('filter:show', function ($event, $someThing, $stack)
{
    if (! preg_match('/^filter:/', $event))
    {
        return array_pop($stack);
    }
    $result = EventManager()-&gt;pipeline($someThing, $stack);
    $result = preg_replace('/\b(\w{3})\b/', '&lt;strong&gt;\1&lt;/strong&gt;', $result);
    return $result;
});

EventManager()-&gt;bind('filter:show', array('Bar', 'the_to_a'));

$bar = new Bar();
EventManager()-&gt;bind('filter:show', array($bar, 'markdown'));

$foo = new Foo();
$foo-&gt;show('The *quick* red fox jumps over the _lazy_ brown dog.');

echo '&lt;hr&gt;';

EventManager()-&gt;unbind('filter:show', $upper4);
$foo-&gt;show('The *quick* red fox jumps over the _lazy_ brown dog.');</code></pre></p>
<p>Output</p>
<pre><strong>a</strong> *quick* <strong>red</strong> <strong>fox</strong> jumps OVER <strong>a</strong> _lazy_ brown <strong>dog</strong>.<hr><strong>a</strong> *quick* <strong>red</strong> <strong>fox</strong> jumps over <strong>a</strong> _lazy_ brown <strong>dog</strong>.</pre>
<p>&#8212;</p>
<h4><strong>EventManager class</strong></h4>
<p>Last but not least, here is the code of the EventManager class</p>
<p><pre class="ln-1"><code class="php">namespace Ando\Core;

require_once &quot;singleton.php&quot;;
require_once &quot;callable.php&quot;;

class EventManager extends Singleton {
     
    /**
     * Stores bindings between events and their handlers
     *
     * @var array
     */
    protected $_bindings = array();
    
    /**
     * Counts bindings
     *
     * @var integer
     */
    protected $_count = 0;
    
    /**
     * Returns TRUE if the given $expression is a regular expression in PHP
     * Matching delimiters (), [], {}, &lt;&gt; are not supported
     *
     * @param $regex
     * @return boolean
     */
    protected function isRegExp( $expression )
    {
        if (is_string( $expression )
                &amp;&amp; preg_match( '/^([^\w \\\\])[^\1]+\1$/', $expression ))
        {
            return true;
        }
        return false;
    }
    
    /**
     * Returns the order of a new handler
     *
     * @return integer
     */
    protected function order()
    {
        return ++$this-&gt;_count;
    }
     
     
    /**
     * Binds a $handler to an $event_template
     *
     * @param string $event_template
     * @param Callable|callable $handler
     * @return Ando\Core\Callable
     */
    public function bind( $event_template, $handler )
    {
        $callable = $handler instanceof Callable
                ? $handler
                : new Callable($handler);
        $handlers = isset($this-&gt;_bindings[ $event_template ])
                ? $this-&gt;_bindings[ $event_template ]
                : new \SplObjectStorage();
        $handlers[ $callable ] = $this-&gt;order();
        $this-&gt;_bindings[ $event_template ] = $handlers;
        return $callable;
    }
     
     
    /**
     * Unbinds a $handler from an $event_template
     *
     * @param string $event_template
     * @param Callable $handler
     */
    public function unbind( $event_template, Callable $handler = null )
    {
        if (is_null( $handler ))
        {
            unset( $this-&gt;_bindings[ $event_template ] );
        }
        else
        {
            unset( $this-&gt;_bindings[ $event_template ][ $handler ] );
            if (0 == $this-&gt;_bindings[ $event_template ]-&gt;count())
            {
                unset( $this-&gt;_bindings[ $event_template ] );
            }
        }
    }
    
    /**
     * Returns true if the $event is compatible with the $event_template
     *
     * @param string $event_template
     * @param string $event
     * @return boolean
     */
    protected function isCompatible( $event_template, $event )
    {
        if ($this-&gt;isRegExp( $event_template ))
        {
            if (! preg_match( $event_template, $event ))
            {
                return false;
            }
        }
        else
        {
            if ($event_template != $event)
            {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Detects the result of an event handler and
     * if stopPropagation has been requested
     *
     * @param mixed $result
     * @return array
     */
    protected function detectResult( $result )
    {
        if (is_array($result) &amp;&amp; isset($result['stopPropagation']))
        {
            $stopPropagation = $result['stopPropagation'];
            $result = isset($result['result']) ? $result['result'] : null;
            return array($result, $stopPropagation);
        }
        return array($result, false);
    }
    
    /**
     * Returns an array with all the handlers that must be called,
     * preserving the order in which the bind occurred
     *
     * @param $event
     * @return array
     */
    protected function filteredHandlers( $event )
    {
        $result = array();
        foreach ($this-&gt;_bindings as $event_template =&gt; $handlers)
        {
            if (! $this-&gt;isCompatible($event_template, $event))
            {
                continue;
            }
            foreach ($handlers as $handler)
            {
                $order = $handlers[ $handler ];
                $result[ $order ] = array(
                    'event_template' =&gt; $event_template,
                    'handler'        =&gt; $handler,
                );
            }
        }
        ksort($result);
        return $result;
    }
    
    /**
     * 1: Dispatches an $event to all of its matching handlers
     * 2: Passes to each matching handler all received arguments plus a stack
     * with previous outcomes (see below)
     * 3: Returns a stack with all the outcomes (see below)
     *
     * The same stack is passed to each handler by reference (all other
     * arguments are passed by value) and finally is returned to the trigger
     * caller.
     *
     * When the stack is returned, each element is a handler outcome, that is an
     * array with keys 'event_template', 'event', 'handler', and 'result'.
     * The order is the same in which the handlers were processed.
     *
     * When the stack is passed to a handler, its elements are all the previous
     * handlers outcomes as described above, plus a special last element. It is
     * an array with a key 'event_template', whose value is the event_template
     * matched by the $event.
     *
     * @param string $event
     * @return array
     */
    public function trigger( $event )
    {
        $stack = array();
        $args = func_get_args();
        $work = $this-&gt;filteredHandlers($event);
        foreach ($work as $task)
        {
            $event_template = $task['event_template'];
            $handler        = $task['handler'];
            
            $stack[] = array('event_template' =&gt; $event_template);
            $count = count($stack);
            $result = $handler($args, $stack);
            list($result, $stopPropagation) = $this-&gt;detectResult($result);
            if (count($stack) == $count)
            {
                $stack[ $count - 1 ] = array(
                    'event_template' =&gt; $event_template,
                    'event'          =&gt; $event,
                    'handler'        =&gt; $handler,
                    'result'         =&gt; $result,
                );
            }
            if ($stopPropagation)
            {
                break;
            }
        }
        return $stack;
    }
    
    /**
     * 1: Returns the second to last value of $stack, if it exists,
     * else returns $someThing
     * 2: It's a utility method for using with handlers that act as filters
     *
     * @param mixed $someThing
     * @param array $stack
     * @return mixed
     */
    public function pipeline($someThing, $stack)
    {
        if (is_array($stack) &amp;&amp; count($stack) &gt; 1)
        {
            $secondToLast = $stack[ count($stack) - 2 ];
            $result = $secondToLast['result'];
        }
        else
        {
            $result = $someThing;
        }
        return $result;
    }
}

Singleton::instance('Ando\Core\EventManager');</code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/yet-another-eventmanager-class-in-php-5-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Submit Form on Enter Key</title>
		<link>http://noteslog.com/post/submit-form-on-enter-key/</link>
		<comments>http://noteslog.com/post/submit-form-on-enter-key/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 09:01:29 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/post/submit-form-on-enter-key/</guid>
		<description><![CDATA[A wonderful trick.]]></description>
			<content:encoded><![CDATA[<p><a href="http://manfred.dschini.org/2007/09/20/submit-form-on-enter-key/" target="_blank">A wonderful trick.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/submit-form-on-enter-key/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yet Another Singleton Class in PHP (5.3)</title>
		<link>http://noteslog.com/post/yet-another-singleton-class-in-php-5-3/</link>
		<comments>http://noteslog.com/post/yet-another-singleton-class-in-php-5-3/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 23:57:17 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=608</guid>
		<description><![CDATA[namespace Ando\Core; class Exception extends \Exception {} abstract class Singleton { /** * Is the repository for instances of subclasses * * @var array */ static private $_instances = array(); /** * 1: Disables the 'new' operation * 2: Calls Singleton::_construct() with all the arguments passed to * Singleton::instance(), except the first one, which is [...]]]></description>
			<content:encoded><![CDATA[<p><pre><code class="php">namespace Ando\Core;

class Exception extends \Exception
{}

abstract class Singleton
{
    /**
     * Is the repository for instances of subclasses
     *
     * @var array
     */
    static private $_instances = array();
    
    /**
     * 1: Disables the 'new' operation
     * 2: Calls Singleton::_construct() with all the arguments passed to
     * Singleton::instance(), except the first one, which is the class name
     * 3: Creates a shortcut for accessing the instance by the class name
     *
     * @param array $args
     */
    private function __construct( $args )
    {
        $init = array($this, '_construct');
        call_user_func_array( $init, $args );
        
        $class = get_class($this);
        preg_match('/^(\\\\?(?:[^\\\\]+\\\\)*)([^\\\\]+)$/', $class, $matches);
        $namespace = $matches[1];
        $function  = $matches[2];
        $shortcut = &quot;
if (! function_exists('$function'))
{
    function $function()
    {
        return Ando\Core\Singleton::instance('$class');
    }
}
&quot;;
        eval($shortcut);
    }
    
    /**
     * Disables the 'clone' operation
     */
    private function __clone()
    {}
    
    /**
     * 1: Initializes the instance
     * 2: Gets called once and automatically by Singleton::instance()
     * 3: Receives all the arguments passed to Singleton::instance(), except the
     * first one, which is the class name
     */
    protected function _construct()
    {}
    
    /**
     * Returns true if there is an instance of the $class in the repository
     *
     * @param string $class
     * @return boolean
     */
    static public function instanceAvailable( $class )
    {
        return isset( self::$_instances[ $class ] );
    }
    
    /**
     * 1: Returns the instance of the $class
     * 2: Creates, initializes and checks the instance the first time it gets
     * called with a given $class name
     *
     * @param string $class
     * @return Singleton
     */
    static public function instance( $class )
    {
        if (! self::instanceAvailable( $class ))
        {
            $args = array_slice( func_get_args(), 1 );
            $instance = new $class( $args );
            if ($instance instanceof self)
            {
                self::$_instances[ $class ] = $instance;
            }
            else
            {
                throw new Exception('Expected a subclass of Ando\Core\Singleton');
            }
        }
        return self::$_instances[ $class ];
    }
}</code></pre><span id="more-608"></span></p>
<p><strong>Example</strong></p>
<p><pre><code class="php">require_once &quot;singleton.php&quot;;

/**
 * Basic
 */
class C extends Ando\Core\Singleton {};

/**
 * Value
 */
class A extends Ando\Core\Singleton
{
	protected $val = null;
	
	public function set($val)
    {
        $this-&gt;val = $val;
    }
    
    public function get()
	{
		return $this-&gt;val;
	}
	
	protected function _construct( $a )
    {
        $this-&gt;set($a);
    }
}

/**
 * Extended Value
 */
class AA extends A
{
    protected function _construct( $a, $b )
    {
        $this-&gt;set(C()-&gt;hello . ($a + $b-&gt;get()));
    }
}



//$test = new A();
//Fatal error: Call to private Ando\Core\Singleton::__construct() from invalid context...

use Ando\Core\Singleton;

Singleton::instance('C')-&gt;hello = 'world';
echo &quot;&lt;p&gt;Now C holds &quot; . C()-&gt;hello . &quot;&lt;/p&gt;&quot;;

Singleton::instance('A', 3);
echo &quot;&lt;p&gt;Now A holds &quot; . A()-&gt;get() . &quot;&lt;/p&gt;&quot;;

Singleton::instance('A', 5);
Singleton::instance('AA', 7, A());
echo &quot;&lt;p&gt;Now AA holds &quot; . AA()-&gt;get() . &quot;&lt;/p&gt;&quot;;

A()-&gt;set(5);
echo &quot;&lt;p&gt;Now A holds &quot; . A()-&gt;get() . &quot;&lt;/p&gt;&quot;;
AA()-&gt;set(5);
echo &quot;&lt;p&gt;Now AA holds &quot; . AA()-&gt;get() . &quot;&lt;/p&gt;&quot;;
$result = AA() === A() ? 'Yes' : 'No';
echo &quot;&lt;p&gt;AA() is A() ? $result&lt;/p&gt;&quot;;

$result = Singleton::instance('A') === A() ? 'Yes' : 'No';
echo &quot;&lt;p&gt;Singleton::instance('A') is A() ? $result&lt;/p&gt;&quot;;


class B
{
    protected $val = 0;
    public function __construct( $b )
    {
        $this-&gt;b = $b;
    }
    
    public function get()
    {
        return $this-&gt;b;
    }
}

//Singleton::instance('B', 1);
//Fatal error: Uncaught exception 'Ando\Core\Exception' with message 'Expected a subclass...</code></pre></p>
<p><strong>Results</strong></p>
<p><p>Now C holds world</p><p>Now A holds 3</p><p>Now AA holds world10</p><p>Now A holds 5</p><p>Now AA holds 5</p><p>AA() is A() ? No</p><p>Singleton::instance('A') is A() ? Yes</p></p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/yet-another-singleton-class-in-php-5-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yet Another EventManager Class in PHP (</title>
		<link>http://noteslog.com/post/yet-another-eventmanager-class-in-php/</link>
		<comments>http://noteslog.com/post/yet-another-eventmanager-class-in-php/#comments</comments>
		<pubDate>Sat, 24 Oct 2009 16:52:32 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=528</guid>
		<description><![CDATA[Some months ago I published an article about How to add events to a PHP project (1st EventManager). It should have been the basis for a later article about how to use events to index a site, still to be written. The 1st EventManager class was ready to use, but some days ago I discovered [...]]]></description>
			<content:encoded><![CDATA[<p>Some months ago I published an article about <a href="http://noteslog.com/post/how-to-add-events-to-a-php-project/" target="_self">How to add events to a PHP project</a> (1st EventManager). It should have been the basis for a later article about how to use events to index a site, still to be written.</p>
<p>The 1st EventManager class was ready to use, but some days ago I discovered the <a href="http://components.symfony-project.org/event-dispatcher/" target="_blank">Event Dispatcher</a> component of symfony (sfEventDispatcher class), whose <a href="http://components.symfony-project.org/event-dispatcher/trunk/book/02-Recipes" target="_blank">Recipes</a> page shows some usage examples. It proved that my EventManager class needed some reworking to have comparable power.<span id="more-528"></span></p>
<p>So I developed my 2nd EventManager class, whose differences with respect to the sfEventDispatcher class are explained below.</p>
<ol>
<li>EventManager is a Singleton</li>
<li>EventManager events are strings</li>
<li>EventManager bind() can attach handlers to regular expressions</li>
<li>EventManager event handler arguments are loosely structured</li>
<li>EventManager event handler return value is loosely structured</li>
<li>EventManager gathers, stores, and eventually returns all handlers results</li>
</ol>
<p><strong>EventManager is a Singleton</strong></p>
<p>The 1st EventManager I described was a singleton by itself, but the 2nd EventManager extends the Singleton class I talked about in the article <a href="http://noteslog.com/post/yet-another-singleton-class-in-php/" target="_self">Yet Another Singleton Class in PHP (&lt;5.3)</a>.</p>
<p>In the Recipes page of the sfEventDispatcher class it is said that a reason for not being it a singleton is that &#8220;you might want to have several concurrent event dispatchers in a single PHP request&#8221;. That&#8217;s not an issue with my Singleton class.</p>
<p><pre class="ln-1"><code class="php">require_once 'event_manager.php';

class AnotherEventManager extends EventManager {}
Singleton::instance('AnotherEventManager');

function hello($event, $world)
{
    echo &quot;Hello $world !&lt;br&gt;&quot;;
}

EventManager()-&gt;bind('hello', 'hello');
//AnotherEventManager()-&gt;bind('hello', 'hello');

AnotherEventManager()-&gt;trigger('hello', 'Popeye');</code></pre></p>
<p>If you run the previous program, you&#8217;ll see nothing, which confirms that AnotherEventManager is not the same EventManager it extends. If you uncomment the commented line, you&#8217;ll see</p>
<pre>Hello Popeye !</pre>
<p>In fact, about a year ago, I used an event manager very similar to sfEventDispatcher (needed injection too)  to automatically reindex a website. It worked fine, but I found it a little hard to use and explain to my colleagues.</p>
<p><strong>EventManager events are strings</strong></p>
<p>Strings are perfect for representing events in PHP, and they don&#8217;t need to be created before triggering, so this approach helps keeping code clean.</p>
<p><strong>EventManager bind() can attach handlers to regular expressions</strong></p>
<p>Events management is inherently asymmetric: it asks for genericity when you bind handlers and specificity when you call them. That&#8217;s why EventManager let&#8217;s you attach a handler to a regular expression (which is a special string in PHP). The handler will then get called whenever a triggered event matches the regular expression it is attached to.</p>
<p><strong>EventManager event handler arguments are loosely structured</strong></p>
<p>All the arguments a trigger is called with, are passed by value (see the note below) to each matching handler.</p>
<p>This is very intuitive. For example, if your trigger is</p>
<p><pre><code class="php">EventManager()-&gt;trigger($foo, $bar, $baz);</code></pre></p>
<p>then a matching handler of yours could be</p>
<p><pre><code class="php">function handler($foo, $bar, $baz) 
{
  //...
}</code></pre></p>
<p>The first argument of a trigger must be an event, so the first argument of a handler is that event. All other arguments are absolutely free form.</p>
<p><strong>EventManager event handler return value is loosely structured</strong></p>
<p>The return value of a handler can be anything.</p>
<p>As a special case, if a handler wants to stop the propagation of the same event to the rest of the handlers, then it can return an array with two keys: &#8216;result&#8217; and &#8216;stopPropagation&#8217;. The former&#8217;s value will be the real result of the handler (and the trigger) and the latter&#8217;s one, if true, will cause EventManager to quit immediately, without further handler processing.</p>
<p><strong>EventManager gathers, stores, and eventually returns all handlers results</strong></p>
<p>Results are pushed on a stack, and eventually the stack is returned to the trigger caller. If the trigger caller wants to know the last result all it needs to do is pop the stack.</p>
<p>The current stack will also be passed by reference (see the note below) to each handler. The last argument a handler receives is in fact the stack that holds the results from all previous handlers, plus a slot (on top) with a bit more data. Those data are just one, for now. It&#8217;s the event template (normal string or regular expression) the current handler was attached to.</p>
<p>Two use cases for the stack follow:</p>
<ol>
<li>If a handler wants to cancel it&#8217;s execution so that it appears as if it was never called, then all it needs to do is pop the stack and return.</li>
<li>If a handler wants to act on the result of a previous handler, then all it needs to do is get to the desired element of the stack.</li>
</ol>
<p>When filtering, the result of a handler feeds the next handler in the pipeline. Such a handler cannot know <em>a priori</em> if it is being executed first or not, so it needs to decide if it takes the input from an argument or from a previous result. This is easy to do using the stack, but EventManager offers a special static method that does it all at once:</p>
<p><pre><code class="php">$input = EventManager::pipeline($anything, $stack);</code></pre></p>
<p>When using stopPropagation, the neat result value is pushed on the stack.</p>
<blockquote><p>Arguments are passed as described, no matter how parameters are declared in the handler: this is a known PHP feature.</p></blockquote>
<p>&#8212;</p>
<p><strong>Recipes</strong></p>
<p>Now I&#8217;ll show what the recipes of sfEventDispatcher become when using EventManager.</p>
<ol>
<li>Action Wrapping, called Doing something before or after a Method Call in sfEventDispatcher docs</li>
<li>Runtime Class Extension, called Adding Methods to a Class in sfEventDispatcher docs</li>
<li>Filters Pipeline, called Modifying Arguments in sfEventDispatcher docs</li>
</ol>
<p><strong>Action Wrapping</strong></p>
<p><pre class="ln-1"><code class="php">class Foo
{
  public function foo()
  {
    //...
    EventManager()-&gt;trigger('action:one:before', 3);
    sleep(3); //an action you want to wrap
    EventManager()-&gt;trigger('action:one:after', null);
    //...
  }
}

class Bar
{
  public function bar()
  {
    //...
    EventManager()-&gt;trigger('action:two:before', 2);
    sleep(2); //another action you want to wrap
    EventManager()-&gt;trigger('action:two:after', null);
    //...
  }
}

class ActionTracerPlugin
{
    public function trace($event, $data)
    {
        if (preg_match('/^action:(.*)$/', $event, $matches))
        {
            $action = $matches[1];
            $time = date('Y-m-d H:i:s');
            $data = var_export($data, true);
            file_put_contents('trace.txt', &quot;$time: $action: $data\n&quot;, FILE_APPEND);
        }
    }
}



require_once 'event_manager.php';

$tracer = new ActionTracerPlugin();
EventManager()-&gt;bind('/:(before|after)$/', array($tracer, 'trace'));

$foo = new Foo();
$foo-&gt;foo();

$bar = new Bar();
$bar-&gt;bar();

$foo-&gt;foo();

echo '&lt;pre&gt;', file_get_contents('trace.txt'), '&lt;/pre&gt;';</code></pre></p>
<p>Trace</p>
<p><pre class="chili-all"><code>2009-10-24 18:31:16: one:before: 3
2009-10-24 18:31:19: one:after: NULL
2009-10-24 18:31:19: two:before: 2
2009-10-24 18:31:21: two:after: NULL
2009-10-24 18:31:21: one:before: 3
2009-10-24 18:31:24: one:after: NULL</code></pre></p>
<p><strong>Runtime Class Extension</strong></p>
<p><pre class="ln-1"><code class="php">class Foo
{
    public function __call($method, $arguments)
    {
        action('__call:start', $method);
        
        $stack = EventManager()-&gt;trigger(__METHOD__, $this, $method, $arguments);
        if (! count($stack))
        {
            action('__call:exception');
            throw new Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
        }

        $result = array_pop($stack);
        action('__call:end', $result);
        return $result;
    }
}

class Bar
{
    public function barMethodForFoo($event, $foo, $method, $arguments, $stack)
    {
        action('barMethodForFoo:start', $arguments);
        if (! ($foo instanceof Foo &amp;&amp; 'bar' == $method))
        {
            array_pop($stack);
            return;
        }
        action('barMethodForFoo:begin');
        
        $someValue = 'Hello ' . $arguments[0] . ' !';

        action('barMethodForFoo:end', $someValue);
        return $someValue;
    }
}

class Baz
{
    public function bazMethodForFoo($event, $foo, $method, $arguments, $stack)
    {
        action('bazMethodForFoo:start', $arguments);
        if (! ($foo instanceof Foo &amp;&amp; 'baz' == $method))
        {
            array_pop($stack);
            return;
        }
        action('bazMethodForFoo:begin');
        
        $someValue = 'I love ' . $arguments[0] . ' !';

        action('bazMethodForFoo:end', $someValue);
        return $someValue;
    }
}

class ActionTracerPlugin
{
    public function trace($event, $data)
    {
        if (preg_match('/^action:(.*)$/', $event, $matches))
        {
            $action = $matches[1];
            $time = date('Y-m-d H:i:s');
            $data = var_export($data, true);
            file_put_contents('trace.txt', &quot;$time: $action: $data\n&quot;, FILE_APPEND);
        }
    }
}

function action($action, $data = null)
{
    EventManager()-&gt;trigger(&quot;action:$action&quot;, $data);
}



require_once 'event_manager.php';

$tracer = new ActionTracerPlugin();
EventManager()-&gt;bind('/^action:/', array($tracer, 'trace'));

$foo = new Foo();
$bar = new Bar();
$baz = new Baz();

EventManager()-&gt;bind('Foo::__call', array($bar, 'barMethodForFoo'));

$foo-&gt;bar(&quot;Olivia&quot;);
    
try
{
    action('baz without bind:before');
    $foo-&gt;baz(&quot;spinach&quot;);
    action('baz without bind:after');
}
catch (Exception $e)
{
    EventManager()-&gt;bind('Foo::__call', array($baz, 'bazMethodForFoo'));
    
    action('baz with bind:before');
    $foo-&gt;baz(&quot;you&quot;);
    action('baz with bind:after');
}

echo '&lt;pre&gt;', file_get_contents('trace.txt'), '&lt;/pre&gt;';</code></pre></p>
<p>Trace</p>
<p><pre class="chili-all"><code>2009-10-24 15:12:44: __call:start: 'bar'
2009-10-24 15:12:44: barMethodForFoo:start: array (
  0 =&gt; 'Olivia',
)
2009-10-24 15:12:44: barMethodForFoo:begin: NULL
2009-10-24 15:12:44: barMethodForFoo:end: 'Hello Olivia !'
2009-10-24 15:12:44: __call:end: 'Hello Olivia !'
2009-10-24 15:12:44: baz without bind:before: NULL
2009-10-24 15:12:44: __call:start: 'baz'
2009-10-24 15:12:44: barMethodForFoo:start: array (
  0 =&gt; 'spinach',
)
2009-10-24 15:12:44: __call:exception: NULL
2009-10-24 15:12:44: baz with bind:before: NULL
2009-10-24 15:12:44: __call:start: 'baz'
2009-10-24 15:12:44: barMethodForFoo:start: array (
  0 =&gt; 'you',
)
2009-10-24 15:12:44: bazMethodForFoo:start: array (
  0 =&gt; 'you',
)
2009-10-24 15:12:44: bazMethodForFoo:begin: NULL
2009-10-24 15:12:44: bazMethodForFoo:end: 'I love you !'
2009-10-24 15:12:44: __call:end: 'I love you !'
2009-10-24 15:12:44: baz with bind:after: NULL</code></pre></p>
<p><strong>Filters Pipeline</strong></p>
<p><pre class="ln-1"><code class="php">class Foo
{
    public function show($someThing)
    {
        $stack = EventManager()-&gt;trigger('filter:show', $someThing);
        $result = array_pop($stack);
        echo $result;
    }
}

class Bar
{
    public function upper4($event, $someThing, $stack)
    {
        if (! preg_match('/^filter:/', $event))
        {
            return array_pop($stack);
        }
        $result = EventManager::pipeline($someThing, $stack);
        $result = preg_replace('/\b(\w{4})\b/e', 'strtoupper(&quot;\1&quot;)', $result);
        return $result;
    }
    
    public function bold3($event, $someThing, $stack)
    {
        if (! preg_match('/^filter:/', $event))
        {
            return array_pop($stack);
        }
        $result = EventManager::pipeline($someThing, $stack);
        $result = preg_replace('/\b(\w{3})\b/', '&lt;strong&gt;\1&lt;/strong&gt;', $result);
        return $result;
    }
    
    public function the_to_a($event, $someThing, $stack)
    {
        if (! preg_match('/^filter:/', $event))
        {
            return array_pop($stack);
        }
        $result = EventManager::pipeline($someThing, $stack);
        $result = preg_replace('/\bthe\b/i', 'a', $result);
        return array('result' =&gt; $result, 'stopPropagation' =&gt; true);
    }
    
    public function markdown($event, $someThing, $stack)
    {
        if (! preg_match('/^filter:/', $event))
        {
            return array_pop($stack);
        }
        $result = EventManager::pipeline($someThing, $stack);
        $result = preg_replace('/_([^_]+)_/', '&lt;em&gt;\1&lt;/em&gt;', $result);
        $result = preg_replace('/\*([^*]+)\*/', '&lt;strong&gt;\1&lt;/strong&gt;', $result);
        return $result;
    }
}



require_once 'event_manager.php';

$bar = new Bar();
EventManager()-&gt;bind('filter:show', array($bar, 'upper4'));
EventManager()-&gt;bind('filter:show', array($bar, 'bold3'));
EventManager()-&gt;bind('filter:show', array($bar, 'the_to_a'));
EventManager()-&gt;bind('filter:show', array($bar, 'markdown'));

$foo = new Foo();
$foo-&gt;show('The *quick* red fox jumps over the _lazy_ brown dog.');</code></pre></p>
<p>Output</p>
<pre><strong>a</strong> *quick* <strong>red</strong> <strong>fox</strong> jumps OVER <strong>a</strong> _lazy_ brown <strong>dog</strong>.</pre>
<p>&#8212;</p>
<p><strong>EventManager class</strong></p>
<p>Last but not least, here is the code of the EventManager class</p>
<p><pre class="ln-1"><code class="php">require_once &quot;singleton.php&quot;;

class EventManager extends Singleton {
     
    /**
     * Stores bindings between events and their handlers
     *
     * @var array
     */
    protected $_bindings = array();
    
    /**
     * Counts bindings
     *
     * @var integer
     */
    protected $_count = 0;
     
    /**
     * Returns the id of the given $handler
     *
     * @param $handler a callable expression
     * @return string
     */
    public function handlerId( $handler )
    {
        if (! is_callable( $handler ))
        {
            throw new Exception('Expected a callable expression');
        }
        if (is_string( $handler ))
        {
            $handler_id = $handler;
        }
        else
        {
            $container = $handler[0];
            $method = $handler[1];
            if (is_string( $container ))
            {
                $class = $container;
                $handler_id = &quot;$class::$method&quot;;
            }
            else
            {
                $class = get_class( $container );
                $object = spl_object_hash( $container );
                $handler_id = &quot;$class::$method::$object&quot;;
            }
        }
        return $handler_id;
    }
     
     
    /**
     * Returns TRUE if the given $expression is a regular expression in PHP
     * Matching delimiters (), [], {}, &lt;&gt; are not supported
     *
     * @param $regex
     * @return boolean
     */
    protected function isRegExp( $expression )
    {
        if (is_string( $expression )
                &amp;&amp; preg_match( '/^([^\w \\\\])[^\1]+\1$/', $expression ))
        {
            return true;
        }
        return false;
    }
    
    /**
     * Returns the order of a new handler
     *
     * @return integer
     */
    protected function order()
    {
        return ++$this-&gt;_count;
    }
     
     
    /**
     * Binds a $handler to an $event_template
     *
     * @param string $event_template
     * @param callable $handler
     * @return EventManager
     */
    public function bind( $event_template, $handler )
    {
        $handler_id = $this-&gt;handlerId( $handler );
        $this-&gt;_bindings[ $event_template ][ $handler_id ] = array(
            'handler' =&gt; $handler,
            'ordered' =&gt; $this-&gt;order(),
        );
        return $this;
    }
     
     
    /**
     * Unbinds a $handler from an $event_template
     *
     * @param string $event_template
     * @param callable $handler
     * @return EventManager
     */
    public function unbind( $event_template, $handler = null )
    {
        if (is_null( $handler ))
        {
            unset( $this-&gt;_bindings[ $event_template ] );
        }
        else
        {
            $handler_id = $this-&gt;handlerId( $handler );
            unset( $this-&gt;_bindings[ $event_template ][ $handler_id ] );
        }
        return $this;
    }
    
    /**
     * Returns true if the $triggered_event is compatible with the $event_template
     *
     * @param string $event_template
     * @param string $triggered_event
     * @return boolean
     */
    protected function isCompatible( $event_template, $triggered_event )
    {
        if ($this-&gt;isRegExp( $event_template ))
        {
            if (! preg_match( $event_template, $triggered_event ))
            {
                return false;
            }
        }
        else
        {
            if ($event_template != $triggered_event)
            {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Detects the result of an event handler and if stopPropagation has been requested
     *
     * @param mixed $result
     * @return array
     */
    protected function detectResult( $result )
    {
        if (is_array($result) &amp;&amp; isset($result['stopPropagation']))
        {
            $stopPropagation = $result['stopPropagation'];
            $result = isset($result['result']) ? $result['result'] : null;
            return array($result, $stopPropagation);
        }
        return array($result, false);
    }
    
    /**
     * Returns an array with all the handlers that must be called
     * preserving the order in which the bind occurred
     *
     * @param $triggered_event
     * @return array
     */
    protected function filteredHandlers( $triggered_event )
    {
        $result = array();
        foreach ($this-&gt;_bindings as $event_template =&gt; $handlers)
        {
            if (! (is_array( $handlers )
                    &amp;&amp; $this-&gt;isCompatible($event_template, $triggered_event)))
            {
                continue;
            }
            foreach ($handlers as $handler_id =&gt; $handler)
            {
                if (! is_callable($handler['handler']))
                {
                    continue;
                }
                $result[ $handler['ordered'] ] = array(
                    'event_template' =&gt; $event_template,
                    'handler_id'     =&gt; $handler_id,
                    'handler'        =&gt; $handler['handler'],
                );
            }
        }
        ksort($result);
        return $result;
    }
    
    /**
     * 1: Dispatches a $triggered_event to all of its matching handlers
     * 2: Passes to each matching handler all received arguments plus a stack
     * with previous results (see below)
     * 3: Returns a stack with all the results (see below)
     *
     * The same stack is passed to each handler by reference (all other
     * arguments are passed by value) and finally is returned to the trigger
     * caller.
     *
     * When the stack is returned, each element has a key and a value. The key
     * is a handler id and the value is its result. The order is the same in
     * which the handlers were processed.
     *
     * When the stack is passed to a handler, its elements are all the previous
     * handlers results as described above, plus a special last element whose
	 * id is the current handler id.
     *
     * The value of that special element is an array with an element whose key
     * is 'event_template' and whose value is the event_template matched by the
     * $triggered_event.
     *
     * @param string $triggered_event
     * @return array
     */
    public function trigger( $triggered_event )
    {
        $stack = array();
        $args = func_get_args();
        $filtered_handlers = $this-&gt;filteredHandlers($triggered_event);
        foreach ($filtered_handlers as $filtered)
        {
            $event_template = $filtered['event_template'];
            $handler_id     = $filtered['handler_id'];
            $handler        = $filtered['handler'];
            
            $stack[ $handler_id ] = array('event_template' =&gt; $event_template);
            $result = call_user_func_array($handler, array_merge($args, array(&amp; $stack)));
            list($result, $stopPropagation) = $this-&gt;detectResult($result);
            if (isset($stack[ $handler_id ]))
            {
                $stack[ $handler_id ] = $result;
            }
            if ($stopPropagation)
            {
                break;
            }
        }
        return $stack;
    }
    
    /**
     * 1: Returns the second to last value of $stack, if it exists,
     * else returns $someThing
     * 2: It's a utility method for using with handlers that act as filters
     *
     * @param mixed $someThing
     * @param array $stack
     * @return mixed
     */
    static public function pipeline($someThing, $stack)
    {
        if (count($stack) &gt; 1)
        {
            $values = array_values($stack);
            $input = $values[ count($stack) - 2 ];
        }
        else
        {
            $input = $someThing;
        }
        return $input;
    }
}

Singleton::instance('EventManager');</code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/yet-another-eventmanager-class-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yet Another Singleton Class in PHP (</title>
		<link>http://noteslog.com/post/yet-another-singleton-class-in-php/</link>
		<comments>http://noteslog.com/post/yet-another-singleton-class-in-php/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 13:45:20 +0000</pubDate>
		<dc:creator>Andrea Ercolino</dc:creator>
				<category><![CDATA[other]]></category>

		<guid isPermaLink="false">http://noteslog.com/?p=508</guid>
		<description><![CDATA[class SingletonException extends Exception {} abstract class Singleton { /** * Is the repository for instances of subclasses * * @var array */ static private $_instances = array(); /** * 1: Disables the 'new' operation * 2: Calls Singleton::_construct() with all the arguments passed to * Singleton::instance(), except the first one, which is the class [...]]]></description>
			<content:encoded><![CDATA[<p><pre><code class="php">class SingletonException extends Exception
{}

abstract class Singleton {
    
    /**
     * Is the repository for instances of subclasses
     *
     * @var array
     */
    static private $_instances = array();
    
    /**
     * 1: Disables the 'new' operation
     * 2: Calls Singleton::_construct() with all the arguments passed to
     * Singleton::instance(), except the first one, which is the class name
     * 3: Creates a shortcut for accessing the instance by the class name
     *
     * @param array $args
     */
    private function __construct( $args )
    {
        $init = array($this, '_construct');
        call_user_func_array( $init, $args );
        
        $class = get_class($this);
        $shortcut = &quot;
if (! function_exists('$class'))
{
    function $class()
    {
        return Singleton::instance('$class');
    }
}
&quot;;
        eval($shortcut);
    }
    
    /**
     * Disables the 'clone' operation
     */
    private function __clone()
    {}
    
    /**
     * 1: Initializes the instance
     * 2: Gets called once and automatically by Singleton::instance()
     * 3: Receives all the arguments passed to Singleton::instance(), except the
     * first one, which is the class name
     */
    protected function _construct()
    {}
    
    /**
     * Returns true if there is an instance of the $class in the repository
     *
     * @param string $class
     * @return boolean
     */
    static public function instanceAvailable( $class )
    {
        return isset( self::$_instances[ $class ] );
    }
    
    /**
     * 1: Returns the instance of the $class
     * 2: Creates, initializes and checks the instance the first time it gets
     * called with a given $class name
     *
     * @param string $class
     * @return Singleton
     */
    static public function instance( $class )
    {
        if (! self::instanceAvailable( $class ))
        {
            $args = array_slice( func_get_args(), 1 );
            $instance = new $class( $args );
            if ($instance instanceof self)
            {
                self::$_instances[ $class ] = $instance;
            }
            else
            {
                throw new SingletonException('Expected a Singleton subclass');
            }
        }
        return self::$_instances[ $class ];
    }
}</code></pre><span id="more-508"></span></p>
<p><strong>Example</strong></p>
<p><pre><code class="php">require_once &quot;singleton.php&quot;;

/**
 * Basic
 */
class C extends Singleton {};

/**
 * Value
 */
class A extends Singleton
{
	protected $val = null;
	
	public function set($val)
    {
        $this-&gt;val = $val;
    }
    
    public function get()
	{
		return $this-&gt;val;
	}
	
	protected function _construct( $a )
    {
        $this-&gt;set($a);
    }
}

/**
 * Extended Value
 */
class AA extends A
{
    protected function _construct( $a, $b )
    {
        $this-&gt;set(C()-&gt;hello . ($a + $b-&gt;get()));
    }
}



//$test = new A();
//Fatal error: Call to private Singleton::__construct() from invalid context...

Singleton::instance('C')-&gt;hello = 'world';
echo &quot;&lt;p&gt;Now C holds &quot; . C()-&gt;hello . &quot;&lt;/p&gt;&quot;;

Singleton::instance('A', 3);
echo &quot;&lt;p&gt;Now A holds &quot; . A()-&gt;get() . &quot;&lt;/p&gt;&quot;;

Singleton::instance('A', 5);
Singleton::instance('AA', 7, A());
echo &quot;&lt;p&gt;Now AA holds &quot; . AA()-&gt;get() . &quot;&lt;/p&gt;&quot;;

A()-&gt;set(5);
echo &quot;&lt;p&gt;Now A holds &quot; . A()-&gt;get() . &quot;&lt;/p&gt;&quot;;
AA()-&gt;set(5);
echo &quot;&lt;p&gt;Now AA holds &quot; . AA()-&gt;get() . &quot;&lt;/p&gt;&quot;;
$result = AA() === A() ? 'Yes' : 'No';
echo &quot;&lt;p&gt;AA() is A() ? $result&lt;/p&gt;&quot;;

$result = Singleton::instance('A') === A() ? 'Yes' : 'No';
echo &quot;&lt;p&gt;Singleton::instance('A') is A() ? $result&lt;/p&gt;&quot;;</code></pre></p>
<p><strong>Results</strong></p>
<p><p>Now C holds world</p><p>Now A holds 3</p><p>Now AA holds world10</p><p>Now A holds 5</p><p>Now AA holds 5</p><p>AA() is A() ? No</p><p>Singleton::instance('A') is A() ? Yes</p></p>
]]></content:encoded>
			<wfw:commentRss>http://noteslog.com/post/yet-another-singleton-class-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
