public function trigger($event, $target = null, array $args = []): EventInterface
    {
        if (!$event instanceof EventInterface) {
            $event = (string)$event;

            if (isset($this->events[$event])) {
                $event = $this->events[$event];
            } else {
                $event = $this->wrapperEvent($event);
            }
        }

        /** @var EventInterface $event */
        if (!$name = $event->getName()) {
            throw new \InvalidArgumentException('The triggered event name cannot be empty!');
        }

        $event->setParams($args);
        $event->setTarget($target);

        // Initial value of stop propagation flag should be false
        $event->stopPropagation(false);

        // have matched listener
        if (isset($this->listeners[$name])) {
            $this->triggerListeners($this->listeners[$name], $event);

            if ($event->isPropagationStopped()) {
                return $event;
            }
        }

        // have matched listener in parent
        if ($this->parent && ($listenerQueue = $this->parent->getListenerQueue($event))) {
            $this->triggerListeners($listenerQueue, $event);
            unset($listenerQueue);
        }

        // like 'app.start' 'app.db.query'
        if ($pos = \strrpos($name, '.')) {
            $prefix = substr($name, 0, $pos);
            $method = substr($name, $pos + 1);

            // have a group listener. eg 'app'
            if (isset($this->listeners[$prefix])) {
                $this->triggerListeners($this->listeners[$prefix], $event, $method);
            }

            if ($event->isPropagationStopped()) {
                return $event;
            }

            // have a wildcards listener. eg 'app.*'
            $wildcardEvent = $prefix . '.*';

            if (isset($this->listeners[$wildcardEvent])) {
                $this->triggerListeners($this->listeners[$wildcardEvent], $event, $method);
            }

            if ($event->isPropagationStopped()) {
                return $event;
            }
        }

        // have global wildcards '*' listener.
        if (isset($this->listeners['*'])) {
            $this->triggerListeners($this->listeners['*'], $event);
        }

        return $event;
    }