方法调用之间的区别$ model-> relation();和$ model->关系;

时间:2015-01-29 19:47:28

标签: php arrays laravel methods

这里有一些我缺少的基本理解/理论。我不明白这些函数调用之间的区别:

$distributors = $store->distributors();
$distributors = $store->distributors;
$distributors = $store->distributors()->get();
$distributors = $store->distributors->get();

我在这里要完成的是获得商店经销商列表(多对多关系),并将每个经销商的啤酒列表放入一个巨大的列表中。

foreach ($distributors as $distributor) 
{
    $available_beers = array_merge($distributor->beers(), $available_beers);
}

我不知道这是否是最好的方法,我无法让它发挥作用。与第一个方法列表类似,我不知道是否需要->$beers->$beers()

更新

感谢所有回答的人!这对我来说将是一个很好的参考。我最大的教训是获取集合与获取查询构建器/关系对象之间的区别。为了将来参考那些发现这个问题的人,这是我在控制器中设置的内容:

$store = $this->store->find($id)->first();
$distributors = $store->distributors;
$beers = [];
foreach ($distributors as $distributor){
    $beers = array_merge($distributor->beers->lists('name', 'id'), $beers);
}

7 个答案:

答案 0 :(得分:44)

简短回答

$model->relation()会返回关系对象

$model->relation会返回关系的结果


答案很长

$model->relation()可以解释得非常简单。您正在调用您定义关系的实际功能。你的distributor可能看起来像这样:

public function distributors(){
    return $this->hasMany('Distributor');
}

因此,在调用$store->distributors()时,您只需获得$this->hasMany('Distributor')的返回值,该值为Illuminate\Database\Eloquent\Relations\HasMany的实例

你什么时候使用它?

如果要在运行查询之前进一步指定查询,通常会调用关系函数。例如,添加where语句:

$distributors = $store->distributors()->where('priority', '>', 4)->get();

当然您也可以这样做:$store->distributors()->get()但结果与$store->distributors相同。


这让我想到动态关系属性的解释。

Laravel做了一些事情,允许您直接访问关系的结果作为属性。喜欢:$model->relation

以下是Illuminate\Database\Eloquent\Model

中发生的事情

1)这些属性实际上并不存在。因此,如果您访问$store->distributors,则会将呼叫代理到__get()

2)然后,此方法使用属性名getAttribute

调用getAttribute('distributors')
public function __get($key)
{
    return $this->getAttribute($key);
}

3)getAttribute中,它会检查关系是否已加载(存在于relations中)。如果不存在,并且如果存在关系方法,则将加载关系(getRelationshipFromMethod

public function getAttribute($key)
{
    // code omitted for brevity

    if (array_key_exists($key, $this->relations))
    {
        return $this->relations[$key];
    }

    $camelKey = camel_case($key);

    if (method_exists($this, $camelKey))
    {
        return $this->getRelationshipFromMethod($key, $camelKey);
    }
}

4)最后,Laravel在关系上调用getResults(),然后在查询构建器实例上生成get()。 (这与$model->relation()->get()给出的结果相同。

答案 1 :(得分:4)

直接回答你的问题:

  • $store->distributors()将返回实际关系对象(\ Illuminate \ Database \ Eloquent \ Relations \ BelongsToMany)。
  • $store->distributors将是一个包含关系查询结果的集合(\ Illuminate \ Database \ Eloquent \ Collection)。
  • $store->distributors()->get()将是一个包含关系查询结果的集合(\ Illuminate \ Database \ Eloquent \ Collection)。
  • $store->distributors->get()应该返回错误,因为您在Collection对象上调用get()并且第一个参数不是可选的。如果不是错误,它至少应该返回null。

更多信息:

鉴于以下模型:

class Store extends Eloquent {
    public function distributors() {
        return $this->belongsToMany('Distributor');
    }
}

调用关系方法($store->distributors())将返回关系(\ Illuminate \ Database \ Eloquent \ Relations \ BelongsToMany)对象。这基本上是一个您可以继续修改的查询对象,但您仍然需要调用某种类型的方法来获取结果(例如get()first()等。)

但是,访问关系属性($store->distributors)将返回一个集合(\ Illuminate \ Database \ Eloquent \ Collection)对象,其中包含执行关系查询的结果。

默认情况下,创建关系属性并在第一次访问时为其分配值(称为"延迟加载")。因此,第一次访问$store->distributors时,它在后台执行关系查询,将结果存储在$store->distributors属性中,然后返回这些结果。但是,它只执行一次。下次访问$store->distributors时,该属性已包含数据,因此您正在访问该数据。

为了说明这一点:

// the following two statements will run the query twice
$r1 = $store->distributors()->get();
$r2 = $store->distributors()->get();

// the following two statements will run the query once.
// the first statement runs the query, populates $store->distributors, and assigns the variable
// the second statement just accesses the data now stored in $store->distributors
$r3 = $store->distributors;
$r4 = $store->distributors;

// at the end, $r1 == $r2 == $r3 == $r4

关系也可以是“渴望”。在查询上使用with()方法加载。这样做是为了减轻延迟加载可能需要的所有额外查询(称为n + 1问题)。您可以阅读有关here的更多信息。

答案 2 :(得分:2)

当你处理与Eloquent的关系时,属性是你的关系白色的集合(Illuminate\Database\Eloquent\Collection),该方法是新查询的开始。

假设您的模型如下:

class User extends Eloquent {

    public function roles()
    {
        return $this->belongsToMany('Role');
    }

}

如果您尝试访问$user->roles,Eloquent将运行查询并通过magic methods获取与该用户相关的所有角色,并返回Illuminate\Database\Eloquent\Collection的实例。该类有一个名为get的方法,这就是为什么$user->roles->get()适合您。

如果您尝试访问方法$user->roles(),则会获得一个查询构建器对象,以便您可以对查询进行微调。

$user->roles()->whereIn('role_id', [1, 3, 4])->get();

这只会返回role_id134的角色。

因此,该属性返回一个完整的查询,结果(Illuminate\Database\Eloquent\Collection),而该方法允许您自定义查询。

答案 3 :(得分:1)

也许这会有用。

访问方法:

$object->method();

获取财产:

$object->property;

答案 4 :(得分:1)

$ distributors = $ store-> distributor(); 方法(功能)的结果

$ distributors = $ store->经销商; 财产的价值(变量)

$ distributors = $ store-> distributor() - > get(); 取第一个,它是方法的结果,如果方法返回一个对象,这是该对象中返回的方法。

$ distributors = $ store-> distributor-> get(); 如果属性是一个对象,那么它在该属性中调用一个对象的方法。

重新> $ beers vs - > $ beers(),它们是属性/方法的动态名称,具体取决于您所使用的内容。只是粗略猜测你正在做什么,在你的课堂上你会有

$ this-> beers = array(' bud',' miller',' sam');

并且在使用$ store对象的代码中,您实际上会像

那样

$ drink_type ='啤酒&#39 ;; $ drink_list = $ store-> $ drink_type;

这将从$ store返回$ this->啤酒,与写$ store->啤酒相同;

答案 5 :(得分:0)

想象一下商店类看起来像这样:

<?php

class Store {

    public $distributors;

    function __construct($distributors = array()) {
        $this->distributors = $distributors;
    }

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

所以区别在于:

$store = new Store(array('some guy', 'some other guy'));
$guys = $store->distributors; # accesing the $distributors property
$more = $store->distributors(); # calling the distributors() method.

答案 6 :(得分:0)

主要区别是:

  • $distributors = $store->distributors()返回关系对象的实例,例如Illuminate\Database\Eloquent\Relations\BelongsToMany。调用此之后,您可以使用其他条件,例如where

  • $store->distributors返回集合Illuminate/Database/Eloquent/Collection的实例。 Laravel在后台调用了魔术方法__get。它将返回查询关系的结果。