通过引用 Laravel 事件侦听器传递数组

Pass array by reference to Laravel Event Listener

我在 Laravel 应用程序中有一个数组,我想在 Laravel 侦听器中对其进行修改。 PHP 默认情况下按值传递数组,但是 Laravel 事件及其侦听器的工作方式我无法修改原始变量。有没有比我下面做的更好的方法?

触发事件的模型。

型号:Event.php

namespace Vendor\Package\Models

use Vendor\Package\Events\PageNodeArrayAfter;
use Event;

class Page
{
   public function toArray()
   {
      $data = []; 

      // do something with the data. 

      Event::fire(new PageNodeToArrayAfter($data))

      // The data should be modified by a listener when I use it here.
   }
}

事件:PageNodeToArrayAfter.php

namespace Vendor\Package\Events;

class PageNodeToArrayAfter
{
    /**
     * Props to be sent to the view
     * @var array $data
     */
    protected $data = [];

    /**
     * @param array $data
     * 
     */
    public function __construct(array &$data)
    {
        $this->data = $data;
    }

    public function getData()
    {
        return $this->data;
    }
}

听众:FlashMessagesListner.php

namespace Vendor\Package\Listeners;

class FlashMessagesListner
{
    protected $data = [];

    public function handle(PageNodeToArrayAfter $event)
    {
       $this->data = $event->getData();
       // The problem here is the $data is no logner a reference here. 
    }
}

根据 array 的文档,内容如下:

Array assignment always involves value copying. Use the reference operator to copy an array by reference.

因此,请将您的构造函数改为:

// prepend the argument with the reference operator &
public function __construct(array &$data) 

我感谢所有回复、对问题的反馈以及寻找更好方法的建议。

现在我没有使用监听器,而是尝试了 Laravel 管道,这是通过不同管道传递数据并在我的例子中过滤数据的好方法。这篇文章对理解它很有帮助https://jeffochoa.me/understanding-laravel-pipelines

这是我的代码的最终版本以及我如何使用 Laravel 管道:

节点:Page.php

<?php declare(strict_types=1);

namespace Vendor\Package\Nodes;


class Page extends ReactPage
{
    public function toArray() : array
    {
        $data = parent::toArray();

        $pipes = [
           AppendFlashMessage::class,
           RemoveEmptyLayoutNode::class
        ];


        // Filter data through the pipelines. 
        $data = app(Pipeline::class)
            ->send($data)
            ->through($pipes)
            ->via('filter')
            ->then(function($data) {
                return $data;
        });

        return $data;
    }
}

管道:AppendFlashMessage.php

<?php declare(strict_types=1);

namespace Vendor\Package\Pipeline;

use Closure;

class AppendFlashMessage
{

    public function filter(array $data, Closure $next) : array
    {

        // step 1: pull the errors from session.
        $errors = [
            'type' => 'error',
            'message' => 'Invalid User Name'
        ];

        $data['messages'] = $errors;
        return $next($data);
    }
}

只需在事件的构造函数中使用引用符号:

/**
 * @param array $data
 * 
 */
public function __construct(array &$data)
{
    $this->data = &$data;
                  ^
}

虽然这提供了问题的准确答案,但我不建议对这个特定用例使用观察者模式。

此外,您不需要访问器 - 只需创建 data 属性 public 并在您的侦听器中使用 $event->data

触发的初始事件通过引用传递(因为它是一个对象)。侦听器执行后可以访问该对象中修改的$data 属性。

  event($e = new PageNodeToArrayAfter($data));
  $data = $e->getData(); 

无需在事件构造函数或getter中通过引用手动传递任何内容。