Tạo một framework MVC làm nền tảng cho lập trình ứng dụng trong PHP

Khi có được kiến thức MVC cơ bản, bạn sẽ thấy thoải mái và dễ dang hơn khi sử dụng những framework như Zend hay Symfony, CakePHP,… MVC cơ bản này cũng sẽ giúp bạn nếu đam mê xây dựng application architect phát triển bổ sung vào nó những công cụ hữu ích khác nếu muốn, tạo nên một framework hoàn chỉnh có thể dùng trong công việc hàng ngày mà ở đó bạn có thể kiểm soát hoàn toàn các đoạn code của mình.

Trước hết, MVC là mô hình gồm 3 thành phần:

– Model: Truy vấn dữ liệu
– View: Hiển thị dữ liệu và nhập liệu
– Controller: Xử lý nghiệp vụ

Như vậy, MVC là mô hình gắn liền với mô hình ứng dụng 3 lớp mà chúng ta đã quen thuộc.

Xử lý tập trung
Xét với 1 ứng dụng website, do bản chất của nó là giao tiếp giữa client (web browser của người dùng) và server (web server) qua các lời gọi Request và trả lời Response, một ứng dụng website có thể cho user truy cập nhiều trang web khác nhau như index.php, user.php, view_product.php,… Việc này dẫn đến nhiều khó khăn khi hệ thống có những biến chia sẻ chung như setting, database access,… Thường thì chúng ta sẽ phải viết code như sau:

{geshibot lang=”php” head=””}<?php
include (‘global.php’); //Các biến dùng chung

// Các xử lý code khác

?>{/geshibot} 

Mô hình MVC sẽ thay đổi việc này bằng cách tập trung tất cả các request của user về một trang duy nhất: index.php sau đó sẽ xử lý bằng cách phân tích request và gọi đúng trang php cần thiết để xử lý. Việc tập trung này sẽ giúp các bạn tiến hành các bước kết nối cơ sở dữ liệu, logging, error handling,… hết sức hiệu quả sau này. Tuy nhiên, trong serie này 5s không thể đề cập hết các chi tiết đó.

Trước tiên, ta sẽ tạo một file .htaccess để thực hiện rewrite URL, thay đổi request về file index.php sẽ có tham số router trong query string như sau:

file .htacess ngang cấp với index.php

{geshibot lang=”php” head=””}RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]{/geshibot}

*Lưu ý: nếu bạn chưa load module mod_rewrite của Apache, phải vào httpd.conf để sửa đổi cấu hình và restart Apache.

Ở đây, router là tham số dùng để thay đổi cách gọi request của user, nó giúp file index.php phân tích nội dung request để chuyển tới file php khác thực hiện xử lý thích hợp.

Cũng giống như thông tin cấu hình ở VD trên, chúng ta sẽ làm vài việc gọi là initialize ứng dụng website của mình:
File index.php

{geshibot lang=”php” head=””}require ‘includes/init.php’;{/geshibot} 

File includes/init.php

{geshibot lang=”php” head=””}<?php
error_reporting (E_ALL); //Thông báo tất cả các lỗi
if (version_compare(phpversion(), ‘5.1.0’, ‘<‘) == true) { die (‘PHP5.1 Only’); } //Framework của chúng ta làm việc trên PHP5

// Constants:
define (‘DIRSEP’, DIRECTORY_SEPARATOR); //Tương thích với môi trường Win hay Unix, ta tìm dúng dấu phân cách dir là  \ hay /

// Get site path
$site_path = realpath(dirname(__FILE__) . DIRSEP . ‘..’ . DIRSEP) . DIRSEP;
define (‘site_path’, $site_path);{/geshibot} 

Tiếp theo, tạo một biến registry để chứa các biến toàn cục trong ứng dụng. Sau này ta sẽ lưu vào đây các biến DB, Logger, Cache, Template,…

{geshibot lang=”php” head=””}$registry = new Registry;{/geshibot} 

Vì chúng ta sẽ rất lười nhác phải viếc các hàm include file và vấn đề đang gặp phải là sẽ phải tạo file Registry.php (chú ý case sensitve nhé) cho class Registry ta đang dùng ở trên nên ta sẽ viết một hàm __autoload() cho PHP5 để nó tự load các file php ứng với class ta cần dùng:

{geshibot lang=”php” head=””}function __autoload($class_name) {
        $filename = strtolower($class_name) . ‘.php’;
        $file = site_path . ‘classes’ . DIRSEP . $filename;

        if (file_exists($file) == false) {
                return false;
        }

        include ($file);
}{/geshibot}

Hàm này PHP5 tự động sẽ gọi khi không tìm thấy class cần dùng trong hệ thống, chúng ta cứ viết và để đó – không cần quan tâm gì thêm. Một điều mà tôi muốn các bạn chú ý là trong một framework, cách đặt tên các file, class, variable,… là rất quan trọng và ảnh hưởng tới cơ chế xây dựng framework, do đó, hãy đế ý tới tên họ các biến, class cho cẩn thận, nhất là chữ hoa/thường vì sau này upload lên host Linux sẽ gặp nhiều vấn đề.

Tạo class Registry
Chúng ta sẽ dùng object của Registry để pass dữ liệu lòng vòng trong ứng dụng tương tự như việc dùng Application[‘abc’] của ASP hay biến $GLOBALS của PHP.

{geshibot lang=”php” head=””}<?php

Class Registry {
        private $vars = array();

function set($key, $var) {
        if (isset($this->vars[$key]) == true) {
                throw new Exception(‘Unable to set var `’ . $key . ‘`. Already set.’);
        }

        $this->vars[$key] = $var;
        return true;
}

function get($key) {
        if (isset($this->vars[$key]) == false) {
                return null;
        }

        return $this->vars[$key];
}

function remove($var) {
        unset($this->vars[$key]);
}
}

?>{/geshibot} 

Chúng ta vừa tạo một Dictionary class. Ý nghĩa của một từ điển là cứ cho tôi một từ khoá (key) tôi sẽ cho ý nghĩa của nó (value). Value-key pair cũng là khái niệm hay dùng nên bạn cũng nên nắm bắt luôn ở đây.

VD sử dụng Registry:

{geshibot lang=”php” head=””}<?php

$registry = new Registry;

// Set some data
$registry->set (‘name’, ‘thietkeso’);

// Get data, using get()
echo $registry->get (‘name’);

// Get data, using array access
echo $registry[‘name’]

?>{/geshibot}

Do tôi cũng lười typing và muốn nhấn mạnh một chút về OOP, ta sẽ implement một interface để biến đối tượng $registry mới tạo thành một array của PHP cho dễ dùng hơn.

Đầu tiên sửa lại class Registry:

{geshibot lang=”php” head=””}class Registry Implements ArrayAccess {{/geshibot}

Sau đó implement 4 method của interface ArrayAccess như sau:

{geshibot lang=”php” head=””}function offsetExists($offset) {
return isset($this->vars[$offset]);
}

function offsetGet($offset) {
return $this->get($offset);
}

function offsetSet($offset, $value) {
$this->set($offset, $value);
}

function offsetUnset($offset) {
unset($this->vars[$offset]);
}{/geshibot}

Bây giờ bạn có thể viết $registry[‘name’] = ‘123’ thay vì $registry->set(‘name’, ‘123’);  . Nếu bạn muốn ứng dụng cái này ở class nào đó cho riêng mình để có thêm vòng lặp foreach chẳng hạn thì bạn thử implement thêm interface Iterator nữa nhé. Bạn hãy tham khảo Standard PHP Lib document ở đây http://www.php.net/~helly/php/ext/spl/

Chúc bạn thành công

FOLLOW US

Leave a Reply

Your email address will not be published. Required fields are marked *