Loading... 最简单的,laravel里get()得到的是一组数据,first()得到的是一个model数据。 从形式上,laravel里每一个model数据(record),在取出的时候都是用的PHP的stdClass来包裹或封装,一个model数据就是一个stdClass,stdClass是一个没有属性和方法的空类,一般用来创建一个匿名对象或将非对象类型转换成对象,这样我们就可以很放便的操作它,动态的添加、删除属性: ```php //实例化一个空对象 $obj = new stdClass(); //给对象动态添加属性或者方法 $obj->name = 'pilishen.com'; $obj->description = '做全球最好的IT实战教程'; ``` 那么,当有多条数据取出来的时候,也即有多个stdClass的时候,我们怎么来展现或包裹呢?就是Collection,集合的意思。 ![file](https://www.pilishen.com/storage/post_images/18/12/19/BdrKLC5i7gu6uRQ6Ky3BCuSc6l1xxHxr1hODKkQg.png) 所以,进一步说,在model数据调取中,laravel first()取到的就是一个stdClass,而get()取到的是多个stdclass,无非是以Collection的形式包裹了起来,下面举个类子列出所有省份: ![file](https://www.pilishen.com/storage/post_images/18/12/19/RIMrjwDOpnCldt6cDJK7bFvIUHM39OV1n5cmjPTd.png) ![file](https://www.pilishen.com/storage/post_images/18/12/19/evOtpurdWsj39hlxYeTKEDIDKQXcEMmxbqiVgq1J.png) 可以看到,因为是取出多条数据,所以返回的是一个`Collection{}`对象,里面包含一个`items[]`数组(序列),在这个序列里,装的就是每一个`stdClass{}`对象,也即具体的每一个`Province`数据。 我们再来打印一下first()方法获取的结果 ![file](https://www.pilishen.com/storage/post_images/18/12/19/LVlNXQahZr7WswH3xUORPr26pnxSaEsgeVAWfyyR.png) 我们可以看到first()方法得到的直接是一个stdClass对象,因为它外层没有`array`包裹了,所以就可以直接在其上面获取各种属性了,比如说可以直接来调用关系(relationship)了,假设我们创建一个 `Province hasMany City` 的例子: ![file](https://www.pilishen.com/storage/post_images/18/12/19/E4kSdpv7TQt6qpGTJE78DCGzTsZLY1BejgvCDKN0.png) 这样我们就可以使用 `Province::fisrt()->cities()`来获取第一个省所属的所有城市,那如果需要获取 id为n 的省的所有城市的话我们可以使用 `Province::find(n)->cities()`, 这里的find()方法得到的也是一个具体到ID了的stdClass 对象。 这里注意的是,关系(eloquent relationship)的调用只能作用于某个具体的Model对象,也即你只有具体到某个Model,某个ID,或者说某个stdclass对象了,才能进一步去调用其所属的关系,而不能直接去一堆Model数据上调用关系,或者说不能直接在一个大的collection对象后面直接取关系, 也即这样`Province::get()->cities()`是不对的,这相当于`Collection{}->cities()`,而这个`Collection{}`本身并没有`cities()`这个关系属性,虽然它里面的每一个`Province model item`拥有这个关系属性,但那就隔着一层了。 好吧,不能在`get()`后面直接调取关系,或者说不能笼统地在一堆数据上直接调取关系,那么,调取关系的正确姿势有哪些? 1. 你可以在`first() last() find() firstOrFail() findOrFail()`这些具体到ID的方法后面直接取关系,比如`Province::fisrt()->cities()` 2. 如果你已经`get()`了,也即已经有一堆数据了,那么可以遍历以后再取每一个的关系,比如: ```php $pros = Province::get(); //或者all() foreach($pros as $pro){ $pro->cities(); } ``` 3. 当然,如果你是要在Blade视图里使用遍历后的关系数据,因为每有一个数据,就要取一次关系,就要执行一次查询,所以你foreach里有n个数据,就查询n遍,就有n个query,再加上你之前get()所有数据的那1个query,所以你页面上总共有`n+1`个query,当你数据很多的时候,就会导致页面特别慢,所以你一旦意识到要在视图里取关系属性,就要在Controller里提前用with方法来预加载所有的关系,例如这样: ```php $pros = Province::with('cities')->get(); //或者all() foreach($pros as $pro){ $pro->cities(); } ``` 这样的话,一次性地取得了所有省份以及每个省份下面的城市关系,背后只是执行了2次query,你在视图里再去遍历的时候,就不用再执行数据查询了,性能就会有较大提升。 很多小白抱怨laravel视图加载慢,不知道他们有没有查看一下自己页面的query执行情况呢?一个视图查询太多的query,换谁都慢~ 当然呢,这些细节其实在我们的[实战系列课程](https://study.163.com/u/pilishen)里都已经讲过了,还没有上车的童鞋,你还在等什么呢? Last modification:March 7, 2023 © Allow specification reprint Like 如果觉得我的文章对你有用,请随意赞赏