Yii框架提供一个代码生成器gii, 我们一般用它来生成模型类代码。模型类是对数据(表)操作进行封装 不过在模型类中你看不到get/set属性的方法,甚至看不到和表字段关联的属性成员变量,但并不影响我们直接操作其属性,仿佛这些属性就在那里一样。 其具体实现
Yii框架提供一个代码生成器gii, 我们一般用它来生成模型类代码。模型类是对数据(表)操作进行封装
不过在模型类中你看不到get/set属性的方法,甚至看不到和表字段关联的属性成员变量,但并不影响我们直接操作其属性,仿佛这些属性就在那里一样。
其具体实现方式,正是一些设计模式和PHP5动态语言特性的一个很好的应用案例。
举个例子,如下一个用户模型类,对应的数据表为users
<?php class User extends CActiveRecord { /** * The followings are the available columns in table 'users': * @var double $Id * @var string $Username * @var string $Password * @var string $Email */ /** * Returns the static model of the specified AR class. * @return CActiveRecord the static model class */ public static function model($className='User') { return parent::model($className); } /** * @return string the associated database table name */ public function tableName() { return 'users'; } }
现在我们想读取一条user记录,首先当然得构造一个User对象
$user = new User();
可以执行一下var_dump($user),你会发现这个$user有个私有的_md属性(模型的元数据),该属性类型为CActiveRecordMetaData。
在这个_md变量中包含了数据表结构定义(Schema)。
究竟执行了什么代码,会构造出这样一个对象,并且读取了数据表结构定义,下面我们来跟踪一下:
1、和其他面向对象语言一样,在调用new创建一个对象时,首先会调用类的构造函数,如下:
/** * Constructor. * @param string $scenario scenario name. See {@link CModel::scenario} for more details about this parameter. */ public function __construct($scenario='insert') { if($scenario===null) // internally used by populateRecord() and model() return; $this->setScenario($scenario); $this->setIsNewRecord(true); $this->_attributes=$this->getMetaData()->attributeDefaults; $this->init(); ...... }可以看到模型的构造函数调用了getMetaData方法,并且还给模型对象的属性成员变量($this->_attributes)赋予了缺省值。
看起来模型对象元数据的构造以及数据表shema的读取和这个函数有关,继续
/** * Returns the meta-data for this AR * @return CActiveRecordMetaData the meta for this AR class. */ public function getMetaData() { if($this->_md!==null) return $this->_md; else return $this->_md=self::model(get_class($this))->_md; }getMetaData函数调用了self::model方法,这个函数我们很熟悉,是一个静态方法,根据类名返回模型类的静态实例。
/** * Returns the static model of the specified AR class. * The model returned is a static instance of the AR class. */ public static function model($className=__CLASS__) { if(isset(self::$_models[$className])) return self::$_models[$className]; else { $model=self::$_models[$className]=new $className(null); $model->_md=new CActiveRecordMetaData($model); $model->attachBehaviors($model->behaviors()); return $model; } }
注意self::$_models是一个单例模式静态变量,你的应用所加载过的模型都被放在该对象数组中统一管理,你可以把它看作集中的模型对象管理器。看来,即使模型不再被实际使用,已经建立的模型对象也不会被释放。上述代码中创建了一个CActiveRecordMetaData对象,即前述的数据表Schema,注意User模型本身被作为其构造函数的参数被传递了进去,这里类似于应用了一种委托的模式,即模型类把获取数据表Schema的任务委托给CActiveRecordMetaData类。继续看下去,
/** * Constructor. * @param CActiveRecord $model the model instance */ public function __construct($model) { $this->_model=$model; $tableName=$model->tableName(); if(($table=$model->getDbConnection()->getSchema()->getTable($tableName))===null) throw new CDbException(Yii::t('yii','The table "{table}" for active record class "{class}" cannot be found in the database.', array('{class}'=>get_class($model),'{table}'=>$tableName))); ...... }
上述代码中getTable($tableName),这里应该是getTable('User')函数调用了CMysqlSchema的loadTable方法,最终通过SQL语句
SHOW FULL COLUMNS FROM ...获取到数据表的结构定义并赋值给了模型对象。
现在我们才刚刚了解到User对象中的元数据和缺省属性成员变量值是怎么来的。
接下来,才是动态语言特性相关部分,我们看看如何通过user对象,来所谓“动态”的操作数据属性的。
数据库中的users表中有Email字段,那么我们现在想给新创建的user对象的Email属性赋值,如下:
$user->Email = 'iefreer@hotmail.com';
如果是传统面向对象语言如c++/java,这里会报编译错误,因为User类没有定义Email成员变量。
而对于PHP5而言,由于语言对动态特性(魔法函数)的支持,这样的调用没有任何问题。我们看看它内部是怎么实现的。
如我之前的PHP语言动态特性文章中所言,设置对象的一个不存在的属性,会触发该对象的__set魔法函数:
/** * PHP setter magic method. * This method is overridden so that AR attributes can be accessed like properties. * @param string $name property name * @param mixed $value property value */ public function __set($name,$value) { if($this->setAttribute($name,$value)===false) { if(isset($this->getMetaData()->relations[$name])) $this->_related[$name]=$value; else parent::__set($name,$value); } }
上述代码中的setAttribute函数会把Email添加到$_attributes这个数组类型的成员变量中,也就是$_attributes充当了模型所对应的数据表属性动态管理器的功能。
再看读取user对象属性的语句:
$email = $user->Email;
类似的,该语句将触发CActiveRecord类的__get魔法函数,会返回$_attributes数组中相应属性的值。
by iefreer

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

WebStorm Mac 버전
유용한 JavaScript 개발 도구

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

mPDF
mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구