【问题标题】:Difference between method calls $model->relation(); and $model->relation;方法调用之间的区别 $model->relation();和 $model-> 关系;
【发布时间】:2015-03-29 04:26:22
【问题描述】:

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

$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);
}

【问题讨论】:

    标签: php arrays laravel methods


    【解决方案1】:

    也许这会有用。

    访问方法:

    $object->method();
    

    访问属性:

    $object->property;
    

    【讨论】:

    • 虽然一般来说对 PHP/对象很有用,但当与 Laravel 和关系相关时,答案会稍微复杂一些。
    • 当然可以,但我认为这个问题是关于基础理论的。
    • 大家都知道->method()是方法调用,->property是php中的属性调用。
    【解决方案2】:

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

    <?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.
    

    【讨论】:

      【解决方案3】:
      $distributors = $store->distributors(); 
      

      方法(函数)的结果

      $distributors = $store->distributors;
      

      属性值(变量)

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

      取第一个,它是方法的结果,如果方法返回一个对象,这是返回的对象中的一个方法。

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

      如果该属性是一个对象,那么它会调用该属性中的一个方法,该方法是一个对象。

      Re -&gt;$beers vs -&gt;$beers() 这是属性/方法的动态名称,具体取决于您的用途。只是粗略地猜测一下你在做什么,在你的课堂上你将有

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

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

      $drink_type = 'beers';
      $drink_list = $store->$drink_type;
      

      这将从$store返回$this-&gt;beers,和写$store-&gt;beers一样;

      【讨论】:

        【解决方案4】:

        当您使用 Eloquent 处理关系时,该属性是您的关系 white 的集合 (Illuminate\Database\Eloquent\Collection),该方法是新查询的开始。

        假设您的模型如下所示:

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

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

        如果您尝试访问方法$user-&gt;roles(),您将获得一个查询构建器对象,以便您可以微调您的查询。

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

        这只会返回role_id134 的角色。

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

        【讨论】:

          【解决方案5】:

          简答

          $model-&gt;relation() 返回关系对象

          $model-&gt;relation 返回关系的结果


          长答案

          $model-&gt;relation() 可以很简单地解释。您正在调用您定义关系的实际函数。你的distributor 可能看起来有点像这样:

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

          所以当调用$store-&gt;distributors() 时,你只会得到$this-&gt;hasMany('Distributor') 的返回值,它是Illuminate\Database\Eloquent\Relations\HasMany 的一个实例

          什么时候用?

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

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

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


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

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

          Illuminate\Database\Eloquent\Model 中发生的事情

          1) 这些属性实际上并不存在。因此,如果您访问$store-&gt;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-&gt;relation()-&gt;get() 相同的结果。

          【讨论】:

          • 非常感谢。我为这个问题挣扎了很多次,但我懒得检查代码。你是怎么知道的?
          • @FlexElektroDeimling 通过阅读文档和源代码 ;)
          【解决方案6】:

          直接回答你的问题:

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

          更多信息:

          给定以下模型:

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

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

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

          默认情况下,关系属性在第一次被访问时被创建并赋值(称为“延迟加载”)。因此,第一次访问$store-&gt;distributors 时,它在后台执行关系查询,将结果存储在$store-&gt;distributors 属性中,然后返回这些结果。但是,它只执行一次。下次访问$store-&gt;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的信息。

          【讨论】:

            【解决方案7】:

            主要区别在于:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-01-01
              • 1970-01-01
              • 2023-03-12
              • 2013-11-04
              • 2016-04-07
              • 1970-01-01
              相关资源
              最近更新 更多