PHP物件导向的第三课:建构式

昨天好好睡了一觉,今天的精神有比较好一些。
昨天头痛了一整天......
原本今天的课程是要讲建构式和继承的,但我发现光是和建构式相关的东西就可以写很多很多。
所以今天这一堂课,我们就专门讲建构式好了。
先来一段程式码:

//基本是建议使用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(){             ↑↑↑↑同物件名称所以这一段也是建构式。    }}

明天就要来讲继承了。这也是非常重要的课题。
物件的多型全靠继承来实作了。

值日生记得擦黑板,倒垃圾。放学回家要乖乖的路上别乱跑。
过马路要看红绿灯,记得扶老太太过马路。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章