为什么 laravel 模型重复数据集以及如何(如果可能)只有一组数据?

Why laravel model duplicates set of data and how (if possible) to have only one set of data?

laravel 模型提供了一种方法,它可以 return 来自另一个关联的 table 结果很方便。

例如,我有一个 table 称为项目和另一个 table 称为反馈,其中反馈 table 存储项目 table 中的一个项目的反馈。因此,要获得 id 为 1 的项目的所有反馈,我将执行:

Item::find(1)->feedback;

下面是对象的打印输出 returned.

Illuminate\Database\Eloquent\Collection Object
(    [items:protected] => Array
       (
           [0] => Feedback Object
               (
                   [table:protected] => feedback
                   [connection:protected] => 
                   [primaryKey:protected] => id
                   [perPage:protected] => 15
                   [incrementing] => 1
                   [timestamps] => 1
                   [attributes:protected] => Array
                       (
                           [id] => 1
                           [rma_id] => 3
                           [item_id] => 8
                           [quo_id] => 0
                           [case_id] => i2eM20160120
                           [line_no] => 000001
                           [content] => test
                           [status] => sent
                           [read] => 0
                           [sender] => Tester
                           [created_at] => 2016-01-20 18:03:44
                           [updated_at] => 2016-01-20 18:03:44
                       )

                   [original:protected] => Array
                       (
                           [id] => 1
                           [rma_id] => 3
                           [item_id] => 8
                           [quo_id] => 0
                           [case_id] => i2eM20160120
                           [line_no] => 000001
                           [content] => test
                           [status] => sent
                           [read] => 0
                           [sender] => Tester
                           [created_at] => 2016-01-20 18:03:44
                           [updated_at] => 2016-01-20 18:03:44
                       )

                   [relations:protected] => Array
                       (
                       )

                   [hidden:protected] => Array
                       (
                       )

                   [visible:protected] => Array
                       (
                       )

                   [appends:protected] => Array
                       (
                       )

                   [fillable:protected] => Array
                       (
                       )

                   [guarded:protected] => Array
                       (
                           [0] => *
                       )

                   [dates:protected] => Array
                       (
                       )

                   [touches:protected] => Array
                       (
                       )

                   [observables:protected] => Array
                       (
                       )

                   [with:protected] => Array
                       (
                       )

                   [morphClass:protected] => 
                   [exists] => 1
               )

       )

)

运行良好,显示只有一个关于 id 为 1 的项目的反馈。

我担心的是数据集在 [attributes:protected][original:protected] 中重复。这只是一个测试案例,真实案例将包含数千个反馈,拥有重复的数据集是对内存的巨大浪费。如果我使用 DB::table('table_name') 方法,则数据集不会重复,但这不太方便。

为什么laravel需要复制模型中的数据?

有没有办法让它return只有一组数据?

目前我正在使用 ->toArray() 来 trim 查询后立即删除不必要的数据,但内存使用仍然存在,因为 laravel 仍在创建该组数据。

虽然很难找到一个好的示例,但它允许您在确定保存之前设置属性。如果您完成许多功能并最终检查是否为最终保存正确设置了所有内容,而不需要将所有内容存储在单独的变量中,这可能会很好。

非常小的例子:

$user = User::find(1);
print_r($user);
$user->name = 'John Doe';
print_r($user);
$user->save();
print_r($user());

Returns 类似于:

第一次打印:

[attributes:protected] => Array
(
   [id] => 1
   [name] => 'Jimmy Doe'
   ...
)
[original:protected] => Array
(
   [id] => 1
   [name] => 'Jimmy Doe'
   ...
)

第二次打印:

[attributes:protected] => Array
(
   [id] => 1
   [name] => 'John Doe'
   ...
)
[original:protected] => Array
(
   [id] => 1
   [name] => 'Jimmy Doe'
   ...
)

第三次打印:

[attributes:protected] => Array
(
   [id] => 1
   [name] => 'John Doe'
   ...
)
[original:protected] => Array
(
   [id] => 1
   [name] => 'John Doe'
   ...
)

只有在 save() 之后数据才真正被保存到数据库中。

Eloquent 的 syncOriginal() 在保存模型时启动():

/**
 * Sync the original attributes with the current.
 *
 * @return $this
 */
public function syncOriginal()
{
    $this->original = $this->attributes;

    return $this;
}

存储原始数据是为了让模型进行脏检查。内部使用脏检查来处理数据库更新。

如果模型不脏并且您尝试保存它,则不会执行任何更新。如果模型是脏的并且您尝试保存它,则只会更新那些脏的字段。

如果您真的想要摆脱这个,您可以覆盖模型上的syncOriginal()syncOriginalAttribute()方法。但是,如果您这样做,则意味着该模型将始终被认为是脏的。 getDirty() 将始终 return 所有属性,而 isDirty() 将始终 return true.

如果您使用时间戳,您还需要覆盖 updateTimestamps() 方法,否则您的 updated_atcreated_at 字段将永远无法设置。

class Feedback extends Model
{
    // ...

    public function syncOriginal()
    {
        return $this;
    }

    public function syncOriginalAttribute($attribute)
    {
        return $this;
    }

    protected function updateTimestamps()
    {
        $time = $this->freshTimestamp();

        $this->setUpdatedAt($time);

        if (! $this->exists) {
            $this->setCreatedAt($time);
        }
    }

    // ...
}

在审查代码时,可能还有其他影响不会立即显现出来。

说了这么多,但是,如果您对内存有这种担忧,您可能需要重新考虑一下您的方法和您尝试做的事情。您真的需要一次加载 1000 条反馈吗?这是可以chunk编辑的操作吗?队列中的单个作业是否可以更好地完成这项工作?等...

考虑到 PHP 的内部工作方式,这应该不是问题。除非 'attributes' 未被修改,否则 'attributes' 只是指向 'original' 的指针(或相反),因此两个数组占用的内存量几乎与仅占用相同的内存量其中之一。这就是为什么当您执行 toArray().

时内存使用不会改变的原因

详情请看这个link: http://blog.ircmaxell.com/2014/12/what-about-garbage.html