public function bind($eventName, $callback, $mode = self::BINDING_MODE_LAST)
    {
        // default alias is ... no alias
        $alias = false;

        // check if callback is aliased
        if ($callback instanceof AliasedCallback) {
            $alias = $callback->getAlias();
            $callback = $callback->getCallback();

            if (!isset ($this->aliases[$alias])) {
                $this->aliases[$alias] = &$callback;
            } else {
                throw new EventException(sprintf('Alias "%s" is already bound to another callback', $alias), EventException::INVALID_CALLBACK);
            }
        } else {
            // check if listener is an alias of a previous listener
            if (is_string($callback) && !is_callable($callback)) {
                if (isset ($this->aliases[$callback])) {
                    $alias = $callback;
                    $callback = $this->aliases[$callback];
                }
            } else {
                $alias = false;
            }
        }

        // check callback validity
        if (!is_callable($callback) && !$callback instanceof CallbacksAggregate && !class_exists($callback)) {
            throw new EventException ('Callback must be a callable, an invokable class name, a service reference or a CallbacksAggregate', EventException::INVALID_CALLBACK);
        }

        if (!isset ($this->listeners [$eventName]) || $mode == self::BINDING_MODE_REPLACE) {
            $this->listeners [$eventName] = [];
        }

        switch ($mode) {
            case self::BINDING_MODE_FIRST :
                if ($alias) {
                    $this->listeners [$eventName] = array_merge([
                        $alias => $callback
                    ], $this->listeners [$eventName]);
                } else {
                    array_unshift($this->listeners [$eventName], $callback);
                }
                break;

            case self::BINDING_MODE_REPLACE :
                // same case because if mode == replace, listeners[eventName] has been emptied
            case self::BINDING_MODE_LAST :
                if ($alias) {
                    $this->listeners [$eventName] [$alias] = $callback;
                } else {
                    $this->listeners [$eventName] [] = $callback;
                }
                break;
        }

        return $this;
    }