2

YII框架学习——有关ActiveRecord的一些坑

 2 years ago
source link: http://neoyeelf.github.io/2015/07/24/YII%E6%A1%86%E6%9E%B6%E5%AD%A6%E4%B9%A0%E2%80%94%E2%80%94%E6%9C%89%E5%85%B3ActiveRecord%E7%9A%84%E4%B8%80%E4%BA%9B%E5%9D%91/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

YII框架学习——有关ActiveRecord的一些坑

2015-07-24

在这里我想总结一下我学习YII框架的过程中,踩过的那些坑。希望能给YII框架的初学者一些帮助,使大家能更快地熟悉YII框架。

1.显式地指明表名。
在使用ActiveRecord类时,你一般会去继承yii\db\ActiveRecord这个基类,在models文件夹中去创建一个自己的类,如下:

namespace app\models;
use yii\db\ActiveRecord;
class Customer extends ActiveRecord

一般在文档里会说,yii会根据类名自动去猜测表名(如以上代码,yii便会自动去关联customer表)。但是这个并不是一直都有效,所以最稳妥的办法还是指明表名,像下面这样。

namespace app\models;
use yii\db\ActiveRecord;
class Customer extends ActiveRecord
* @return string 返回该AR类关联的数据表名
public static function tableName()
return 'customer';

2.在你继承自yii\db\ActiveRecord的类里面不要去声明和相对应表里面的字段同名的公有属性。

<?php
namespace app\models;
use yii\db\ActiveRecord;
class Country extends ActiveRecord {
public $name;
public $population;
public function rules(){
return [
[['name', 'population'], 'required'],
public static function tableName()
return 'country';

在上面的代码中,我在Country类里面申明了2个公有属性name和population,我的country表里有3个字段,分别是自增主键id,name和population。

  • 当你通过$country->load(Yii::$app->request->post())的方式接受数据,然后调用$country->save()的时候,你会发现保存成功了,但是name和population字段都没有插入成功。然后我便尝试着在load数据之后打印了下$country对象。如下:
object(app\models\Country)#55 (10) {
["name"]=>
string(3) "France"
["population"]=>
string(4) "18886000"
["_attributes":"yii\db\BaseActiveRecord":private]=>
array(1) {
["id"]=>
int(47)
...//多余的省略

可以看到其公有属性被成功赋值了,而其私有属性_attributes是一个数组,里面有一个元素id,值为47,查询数据库发现正是刚插入的那一行数据的id,而name和population字段都未插入成功。

  • 之后我将Country类里的两个公有属性删除后,继续执行上述操作,便插入成功了,我也将$country对象打印了出来,如下:
<?php
namespace app\models;
use yii\db\ActiveRecord;
class Country extends ActiveRecord {
public function rules(){
return [
[['name', 'population'], 'required'],
public static function tableName()
return 'country';
object(app\models\Country)#55 (10) {
["_attributes":"yii\db\BaseActiveRecord":private]=>
array(3) {
["name"]=>
string(3) "France"
["population"]=>
string(4) "18886000"
["id"]=>
int(48)
...//多余的省略

可以看到这回name和population的值被填充进了私有属性_attributes中。所以由此我推断,当调用$country->save()方法时,会从_attributes数组中取出key-value对存入数据库对应字段。取数据时也是同理,取出来的字段也是自动填充进_attributes数组。

3.当使用model->load(Yii::$app->request->post())时,如何传递post数据

我用postman(模拟http请求的chrome扩展)模拟传递数据,下面是接受数据的方式。

$country = new Country();
$country->load(Yii::$app->request->post());
var_dump($country);

我在Country类里声明了如下rules:

public function rules()
return [
[['name', 'population'], 'required'],

当我用postman模拟post方式在form data里面传递了name和population2个参数时,将$country对象打印出来:

object(app\models\Country)#65 (8) {
["_attributes":"yii\db\BaseActiveRecord":private]=>
array(0) {
...//多余的省略

可以看到其私有变量_attributes并没有被填充进数据。

阅读Model->load()的源码:

public function load($data, $formName = null)
$scope = $formName === null ? $this->formName() : $formName;
if ($scope === '' && !empty($data)) {
$this->setAttributes($data);
return true;
} elseif (isset($data[$scope])) {
$this->setAttributes($data[$scope]);
return true;
} else {
return false;

发现$scope变量为相对应的表名,然后isset($data[$scope])查看的是以对应表名为key的数组,$this->setAttributes($data[$scope])是将对应表名的数组里的key-value对填充进私有属性_attributes。

所以当你模拟post传参时,要传递Country[name]和Country[population],这样才能被load()方法正确接收。修改传参后再次打印$country对象:

object(app\models\Country)#65 (8) {
["_attributes":"yii\db\BaseActiveRecord":private]=>
array(2) {
["name"]=>
string(3) "aaa"
["population"]=>
string(5) "34343"
...//多余的省略

当然你也可以不用load()方式接受数据,你也可以通过以下2种方式进行赋值。
(1)通过批量赋值的方式:
$country->attributes = Yii::$app->request->post();
(2)逐个赋值的方式:
$name = Yii::$app->request->post('name'); $country->name = $name;

上一篇:PHP的基础知识


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK