昨天好好睡了一觉,今天的精神有比较好一些。
昨天头痛了一整天......
原本今天的课程是要讲建构式和继承的,但我发现光是和建构式相关的东西就可以写很多很多。
所以今天这一堂课,我们就专门讲建构式好了。
先来一段程式码:
//基本是建议使用mysqli或是pdo,不过目前市面书籍很多还是只介绍mysql指令集mysql_connect('localhost','root','password');mysql_select_db('mydb');mysql_query("SET NAMES 'utf8'");$sql = "SELECT * FROM `user` WHERE name = 'sam'";$result = mysql_query($sql);if($result != false) while($row = mysql_fetch_object($result)){ echo $row->name.'<br/>'; }}
观众:ㄟㄟㄟ!你给我等等,你是在上物件导向,说要教建构式,你写个mysql读取的程式码干嘛?
这……这当然和我的主题有关係啦。
回到物件这边:
各位都知道,线上游戏的技能有分「主动技」和「被动技」。
观众:你离题了......
所谓的主动技能是玩家要自己去发动的技能,而所谓的被动技就是指会自动去处理的技能。
前面所介绍的物件导向的方法(method),都是必须外部去呼叫执行该物件的方法才会进行动作。
但有的时候会有一种状况就是每一次执行该物件都「必须」先执行某个或是一连串的动作。
这其实相当麻烦。
像上面那一段mysql语法,可能一些人会想说那我用函式包起来,以候呼叫函式就好了。
于是就变成了这样:
function db_connect($host,$username,$password,$dbs){ mysql_connect($host,$username,$password); mysql_select_db($db); mysql_query("SET NAMES 'utf8'");}db_connect('localhost','root','password','mydb');
是的,大致上来说这样看起来算是颇为完美。
也有人乾脆就整个参数写在程式内直接叫db_connect();
可问题是你每次去执行sql资料库时,若要像第一段那样来上一段。
相对的很麻烦。
用上述的函式处理其实很ok,只不过在更详细的物件操作上,有绝对比较好的简单做法。
我们将上面的code转换成物件。
class db{ public $host = 'localhost'; public $username = 'root'; public $password = 'password'; public $database = 'mydb'; function __construct(){ $this->sql_connect(); $this->sql_database(); $this->set_db_encode(); } function sql_connect(){ return @mysql_connect($this->host,$this->username,$this->password); } function sql_database(){ return @mysql_select_db($this->database); } function set_db_encode(){ return mysql_query("SET NAMES 'utf8'"); }}$db = new db;
在这个code中,我们看到了一个很特别的方法名称:__construct();
这个__construct()就是我今天的主体:建构式。
观众:你讲了那么大一串,现在才讲到?不过......什么是建构式?
这边就如我先前说的,你想要使用sql功能,每一次都要做连线、选资料库、编码。
这样每次写实在很累。包成函式是不错的方法,但封装成物件有他接下来使用上的绝对优势。
而所谓的建构式,其意义为:
『当物件生成的同时,强制预先去实作执行物件本身的功能。』
也就是说,当我$db = new db;时。
sql_connect(),sql_database()及set_db_encode()这三个方法会被强制先执行。
这边我得提一些基本的编写概念。
基本上建构式(亦称建构子)并没有规範你一定得怎么写里面的程式码。
你要在里面echo、if、for、while、捞资料库、做坏事、搞破坏.................
都跟你平常正常写程式是一样的。
但是,基于让程式码可维护。
也因此对于建构式就会有基本二个原则:
1.建构式仅用来做为设置预设属性值的存在。
例:
class demo{ function __construct($name){ $this->name = $name; }}$demo = new demo('sam');
※先前未交建构式前,各位会发现我new物件时并不会在物件的名称加上括号:
$demo = new demo;
但是如果你的建构式中是必须给予参数的情形下,你就必须加上括号:
$demo = new demo('sam');
如果你本身对于这方面加与不加不是很肯定,其实我建议你可以全都加括号:
$demo = new demo();
2.建构式仅用来做为预载函式功能执行的存在:
class demo function __construct(){ $this->Action(); } function Action(){ }}
除了这二件事情外,仅可能的不要拿建构式去做其他多余的事。
※在某些framework,因为建构式的内容应该要继承于其父类别的建构式,通常为了避免建构
式的父体子体产生误会,我习惯在子物件的建构式用以下的做法:
class demo extends CI_Controller(){ function __construct(){ parent::__construct(); $this->_init(); } private function _init(){ //这才是真正写建构式要预载功能的地方。 } }
因为这边还没讲到继承,上面的code只是说明一个编写习惯。
这个code在讲继承时会再出现。
了解上面二点在建构式中基于编程式码易读易维护的方法后。
相信你们就比较了解建构式在物件中所扮演的角色。
接下来,我要全面的改写第一段code的内容:
class db{ public $host = 'localhost'; public $username = 'root'; public $password = 'password'; public $database = 'mydb'; public $result; function __construct(){ $this->sql_connect(); $this->sql_database(); $this->set_db_encode(); } function sql_connect(){ return @mysql_connect($this->host,$this->username,$this->password); } function sql_database(){ return @mysql_select_db($this->database); } function set_db_encode(){ return mysql_query("SET NAMES 'utf8'"); } function query($sql_string){ $result = mysql_query($sql_string); $query = new db_query($result); return $query; }}class db_query{ private $result; function __construct($result){ $this->result = $result; } function result(){ $query = array(); if($this->result != false){ while($row = mysql_fetch_object($this->result)){ $query[] = $row; } return $query; } return false; }}$db = new db;$query = $db->query("SELECT * FROM `user` WHERE name = 'sam'");foreach($query->result() as $row){ echo $row->name.'<br/>';}
这一段code可能複杂了些。
因为他是使用了预载sql连线以及特别的db_query资料查询法。
但是你可以发现最后的执行就只是实体化db,然后将sql字串交给db物件的query处理。
最后db的query会回传一个资料集合的物件。
你可以直接从资料物件中取得资料。
(事实上整个db能做的事情是非常多的,透过query物件来取得各种query或是row是很方便的事情,而db本身也可以直接去处理insert、update、delete…等等三功能。)
我们看到了db物件的建构式来做资料库连线。
然后将产生的$result传到query物件,而query物件的建构式就直接指定了$this->result这个属性的值,对于后续的许许多多处理就很轻易的能够解决。
后记:这次的课程我想我用了较为複杂的mysql来解释建构式,也带了点处理sql方法的意味。
但我想或许有些人觉得複杂了一些些。因此这边我用比较白话的文字来做个总结:
『__construct()建构式,其目的在于当物件被实体化的同时,预先执行要一同载入或执行的功能』。
另外相关于建构式还有一个叫做解构式的东西__destruct();通常因为物件执行完就会被自动销毁所以我就没有提到解构式,将来有机会再稍做说明。
再来有关同名函式也是建构式这件事这边我就随便带过了,因为PHP5开始我们强烈建议使用__construct()而不要使用同物件名的函式。所以下面这个例子也是建构式,但不再建议使用。
class demo{ function demo(){ ↑↑↑↑同物件名称所以这一段也是建构式。 }}
明天就要来讲继承了。这也是非常重要的课题。
物件的多型全靠继承来实作了。
值日生记得擦黑板,倒垃圾。放学回家要乖乖的路上别乱跑。
过马路要看红绿灯,记得扶老太太过马路。