Как настроить поведение метода, не используя наследование

Действия до или сразу после вызова метода

Если вы хотите сделать что-либо прямо перед или сразу после того, как вызван метод, вы можете соответственно развернуть метод в начале или в конце метода:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CustomMailer
{
    // ...

    public function send($subject, $message)
    {
        // развернуть событие перед методом
        $event = new BeforeSendMailEvent($subject, $message);
        $this->dispatcher->dispatch('mailer.pre_send', $event);

        // получить $foo и $bar из события, они могли быть изменены
        $subject = $event->getSubject();
        $message = $event->getMessage();

        // настоящая реализация метода здесь
        $ret = ...;

        // сделать что-то после метода
        $event = new AfterSendMailEvent($ret);
        $this->dispatcher->dispatch('mailer.post_send', $event);

        return $event->getReturnValue();
    }
}

В этом примере, вызываются два события: mailer.pre_send до выполнения метода, и mailer.post_send - после. Каждое из них использует пользовательский класс события, чтобы передавать информацию слушателям двух событий. Например, BeforeSendMailEvent может выглядеть так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// src/AppBundle/Event/BeforeSendMailEvent.php
namespace AppBundle\Event;

use Symfony\Component\EventDispatcher\Event;

class BeforeSendMailEvent extends Event
{
    private $subject;
    private $message;

    public function __construct($subject, $message)
    {
        $this->subject = $subject;
        $this->message = $message;
    }

    public function getSubject()
    {
        return $this->subject;
    }

    public function setSubject($subject)
    {
        $this->subject = $subject;
    }

    public function getMessage()
    {
        return $this->message;
    }

    public function setMessage($message)
    {
        $this->message = $message;
    }
}

А AfterSendMailEvent даже так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/AppBundle/Event/AfterSendMailEvent.php
namespace AppBundle\Event;

use Symfony\Component\EventDispatcher\Event;

class AfterSendMailEvent extends Event
{
    private $returnValue;

    public function __construct($returnValue)
    {
        $this->returnValue = $returnValue;
    }

    public function getReturnValue()
    {
        return $this->returnValue;
    }

    public function setReturnValue($returnValue)
    {
        $this->returnValue = $returnValue;
    }
}

Оба события позволяют вам получить некоторую информацию (например, getMessage()) и даже изменить её (например, setMessage()).

Теперь, вы можете создавать подписчик событий, подключающийсяк этому событию. Например, вы можете слушать событие mailer.post_send и изменять возвращённое значение метода:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/AppBundle/EventSubscriber/MailPostSendSubscriber.php
namespace AppBundle\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use AppBundle\Event\AfterSendMailEvent;

class MailPostSendSubscriber implements EventSubscriberInterface
{
    public function onMailerPostSend(AfterSendMailEvent $event)
    {
        $ret = $event->getReturnValue();
        // изменить исходное значение ``$ret``

        $event->setReturnValue($ret);
    }

    public static function getSubscribedEvents()
    {
        return array(
            'mailer.post_send' => 'onMailerPostSend'
        );
    }
}

Вот и всё! Ваш подписчик должен быть вызван автоматически (или прочтите больше о конфигурации подписчика событий).

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.