当前位置: 首页 > 后端技术 > PHP

LaravelEloquent的Fill方法解析

时间:2023-03-30 02:36:45 PHP

上次分析了Laravel中的模型事件和观察者模式,这次来分析一下Eloquent中的填充。用过Laravel的童鞋应该都知道fill方法是给Eloquent实例赋属性的方法。我们先点击fill方法看一下它的源码:笔者这里使用的版本是Laravel5.5最新版本。为了阅读方便,删除了注释publicfunctionfill(array$attributes){$totallyGuarded=$this->totallyGuarded();foreach($this->fillableFromArray($attributes)as$key=>$value){$key=$this->removeTableFromKey($key);如果($this->isFillable($key)){$this->setAttribute($key,$value);}elseif($totallyGuarded){thrownewMassAssignmentException($key);}}return$this;}首先可以看到Laravel会先调用自己的totallyGuarded方法,让我们点击这个方法:publicfunctiontotallyGuarded(){returncount($this->getFillable())==0&&$this->getGuarded()==['*'];}可以看到这个方法的作用是获取自己的fillable和guarded,然后判断他们是否不可批量赋值,最后返回一个Booleanvalue//返回一个True或False的布尔值//如果fillable和guarded都没有设置,则返回True(注意,在这种情况下,Next这个`Model`是不允许批量赋值任何属性的)//否则,返回False$totallyGuarded=$this->totallyGuarded();好了,我们回到刚才的fill方法,继续往下看。接下来是一个foreach循环,但是在循环之前,Laravel会对传入的assigned属性执行fillableFromArray方法,然后点击查看,protectedfunctionfillableFromArray(array$attributes){if(count($this->getFillable())>0&&!static::$unguarded){returnarray_intersect_key($attributes,array_flip($this->getFillable()));}return$attributes;}该方法会检测你是否在fillable数组中定义了值,如果定义了值,则返回fillable和attributes的交集的值,如果没有,则返回属性本身,然后返回fill,调用fillableFromArray处理参数后,现在返回值只是我们允许批量赋值的属性(如果你定义的话)循环第一行,先用removeTableFromKey处理参数Key,删除key中的表name,这个方法就不过多解释了,只是一个字符串拆分和取值的函数$key=$this->removeTableFromKey($key);然后往下看,Laravel调用了每个待填充的属性isFillable方法来保证这个属性可以被填充,我们来看看它的源码:publicfunctionisFillable($key){if(static::$unguarded){返回真;}if(in_array($key,$this->getFillable())){返回真;}if($this->isGuarded($key)){返回false;}返回他们pty($this->getFillable())&&!Str::startsWith($key,'_');}可以看到在这个方法中,Laravel首先判断Model是否被守卫。model没有被保护,所以直接返回Truein_array($key,$this->getFillable())){returntrue;}如果这个属性不存在于可填充数组中,那么Laravel会再次判断这个属性是否存在于保护数组中,如果存在于这个array,then这个属性不是可以批量赋值的属性,所以会直接返回Falseif($this->isGuarded($key)){returnfalse;}如果以上都不满足,那么Laravel会判断itsownfillableattheendarrayisemptyandthispropertystartswith_,thenreturnabooleanvaluereturnempty($this->getFillable())&&!Str::startsWith($key,'_');然后回到fill方法再看,如果这个属性通过了isFillable方法的过滤,那么就把这个属性赋值给自己(因为时间有限,setAttribute方法就不细说了~),$this->setAttribute($键,$值);如果没有通过isFillable方法,那么Laravel会判断自己的Model是否处于不限制任何属性批量赋值的状态,如果不是,那么Laravel会直接抛出Exception//判断这个属性是否通过测试if($this->isFillable($key)){//把这个属性赋给自己$this->setAttribute($key,$value);//如果没通过测试,再判断自己`Model`是否不可批量赋值,如果是,则抛出`Exception`}elseif($totallyGuarded){thrownewMassAssignmentException($key);}检测到所有属性并赋值后,Laravel会返回自己到返回$这个;解析后,以上就是fill方法的源码~,最后是一个总结。当你调用fill方法时,Laravel会先检测当前的Model状态。当你设置fillable数组时,如果没有设置guarded数组,那么Model会处于只能批量赋值指定属性的状态。如果没有设置fillable数组,而是设置了guarded数组,那么Model会处于任意属性都可以批量赋值的状态。至于你同时设置fillable和guardedarrays的情况就不讨论了,因为这样做本身就是Laravel禁止的。然后调用fillableFromArray获取属性和可填充数组的交集。如果你没有定义fillable或disableguards,那么这个方法会直接返回属性,Laravel会在返回的数组上做一个循环。在这个循环中,Laravel会为每个属性调用isFillable方法来检查该属性是否可以填充。如果没有通过该方法的检测(不存在于可填充数组中且没有设置保护数组或存在于保护数组中),那么Laravel会检查当前Model是否处于只有指定的状态可以批量分配属性。如果是,则直接抛出Exception,Laravel会在赋值操作完成后返回$this。Eloquent中fill方法的源码分析~,Laravel的源码还是很清晰易懂的~,不得不再次佩服Laravel的设计,不愧是大师级的框架