() translation by (you can also view the original English article)
Website càng ngày càng trở nên năng động và tương tác với người dùng nhiều hơn, lập trình viên thường tìm kiếm các framework để giúp họ xây dựng nhanh chống các website và ứng dụng web. Hiện tại, có rất nhiều framework tốt, chúng ta có thể sử dụng nó. Tuy nhiên, một framework do ta tự xây dựng sẽ cho ta khả năng tùy chỉnh theo yêu cầu của chúng ta một cách dễ dàng và nhanh chống - bởi vì chúng ta đã biết dữ liệu đầu vào và đâu ra của nó. Trong loạt bài này, chúng ta sẽ xây dựng một PHP5 framework "cây nhà lá vườn của chúng ta ^_^" Nào chúng ta hãy bắt đầu.
Bước 1 : Mở đầu
Trong loạt bài này, chúng ta sẽ xây dựng một PHP5 framework từ con số 0. Framework chúng ta xây dựng sẽ có các tính năng căn bản của một hệ thống quản lý nội dung (CMS) và sẽ dùng nó để xây dựng một hệ thống danh bạ cho một tổ chức nhỏ trên nền web-base.
Hy vọng, sau loạt bài này, bạn sẽ cải tiến framework này để sử dụng cho mục đích của bạn, tuy nhiên, trong loạt bài này, chúng ta chỉ đặc mục đích là xây dựng một framework đơn giản.



Trong vài tuần tới, chúng ta sẽ xem qua các vấn đề sau :
- Tạo cơ chế xác thực, truy cập dữ liệu và quản lý template.
- Gắn kết các chức năng trên lại với nhau
- Sử dụng framework để quản lý nội dung và quyền hạn của site chúng ta.
- Tạo một thiết kế cho trang chủ
- Thiết kế cách thức đăng nhập
- Làm thế nào để framework có thể mở rộng và phát triển
Bước 2: Các mẫu thiết kế (Design Pattern) và ứng dụng chúng vào framework của chúng ta
Khi bạn tạo bất kỳ chương trình máy tính, hệ thống mạng hay một ứng dụng web, thì luôn luôn đòi hỏi phải có một kiến trúc kết hợp với quá trình thực hiện.
Các mẫu thiết kế sẽ bàn về các vấn đề này, và chúng ta sẽ ứng dụng một vài mẫu thiết kế vào framework của chúng ta, để bảo đảm rằng chúng ta có một framework chất lượng, linh hoạt, tương thích và có thể sử dụng được bất kỳ mục đích gì. Trong bài này, chúng ta sẽ sử dụng tìm hiểu 2 mẫu thiết kế là Singleton và Registry.
Bước 3: Tập tin và Thư mục
Việc đầu tiên khi xây dựng framework là phải tạo một cấu trúc phù hợp, để có thể đặt mọi thứ vào. Như các tập tin quan trọng của framework, chúng ta cũng cần tạo một nơi dự phòng cho các tập tin liên quan đến website. Hầu như các website và ứng dụng web đều có các thành phần như sau:
- Các hàm / các đối tượng dùng chung.
- Xữ lý nghiệp vụ.
- Một thiết kế
Các tập tin liên quan đến 3 loại trên nên được nhóm lại với nhau. Xem qua cấu trúc thư mục phía dưới, chúng tôi sẽ giải thích cho cấu trúc này

Lưu ý : thư mục .setting và tập tin .project được tạo ra bởi IDE nên bạn không cần quan tâm.
Các hàm và đối tượng chính như truy cập cơ sở dữ liệu, xát thực người dùng, xữ lý template, đối tượng gửi email, đối tượng phân tách email nên được nhóm vào trong một thư mục gọi là objects bên trong thư mục PCARegistry. Việc này cho phép chúng ta tách biệt các hàm, các đối tượng, các lớp liên quan giữa xữ lý nghiệp vụ và hệ thống.(thông thường các hàm, các đối tượng, các lớp xữ lý hệ thống sẽ được lưu trong Registry)
Tiếp theo, chúng ta cần một nơi để lưu trữ các tập tin liên quan đến xữ lý nghiệp vụ. Chúng ta nên để các tập tin này trong thư mục controllers. Mỗi nghiệp vụ (như danh sách các danh bạ, quản lý nội dung, quản lý bộ sưu tập) nên được tách biệt và lưu trữ trong từng thư mục riêng bên trong thư mục controllers. ,Và nó sẽ không được sử dụng trong bài này, nhưng nó là quan trọng và cần phải có, nên chúng ta cần phải biết nó làm việc như thế nào.
Các thiết kế và template nên được lưu trữ trong thư mục skins. Và chúng ta cũng muốn có nhiều thiết kế khác nhau nên chúng ta cũng nên tách biệt thành từng thư mục riêng cho mỗi thiết kế và đặc nó trong thư mục skins.
Bước 4: The Registry
Các tính năng quan trọng của framework như là truy cập cơ sở dữ liệu, xác thực người dùng ... Bằng việc thực thi mẫu thiết kế Registry, chúng ta có thể giữ cho các đối tượng này được lưu trữ tập trung vào một nơi là Registry, nó sẽ cho phép chúng ta truy cập dễ dàng trong framework của chúng ta hoặc bất cứ một ứng dụng nào kế thừa framework của chúng ta.
Mẫu thiết kế Registry lưu trữ và truy lục các tham chiếu của các đối tượng, và nó làm việc tương tự như danh bạ điện thoại. Chúng ta sẽ dùng Registry để lưu trữ các đối tượng cốt lõi, các tham số cấu hình hệ thống hoặc bất cứ thông tin nào muốn chia sẽ trong toàn bộ hệ thống.
Bởi vì chúng ta lưu trữ các thông tin này tập trung, nên chúng ta chỉ cần một thể hiện (instance) của đối tượng registry trong toàn bộ framework của chúng ta, và nếu có nhiều hơn một thì chúng ta đã gặp vấn đề Để giải quyết vấn đề này, đối tượng Registry của chúng ta cần thực thi mẫu thiết kế Singleton, nó sẽ bảo đảm chỉ có một thể hiện có hiệu lực trong suốt framework của chúng ta.
Phía dưới là code PHP của tập tin registry.class.php, chúng ta sẽ nghiên cứu nó làm việc như thế nào.
1 |
|
2 |
<?php
|
3 |
/**
|
4 |
* The PCARegistry object
|
5 |
* Implements the Registry and Singleton design patterns
|
6 |
*
|
7 |
* @version 0.1
|
8 |
* @author Michael Peacock
|
9 |
*/
|
10 |
class PCARegistry { |
11 |
|
12 |
/**
|
13 |
* Our array of objects
|
14 |
* @access private
|
15 |
*/
|
16 |
private static $objects = array(); |
17 |
|
18 |
/**
|
19 |
* Our array of settings
|
20 |
* @access private
|
21 |
*/
|
22 |
private static $settings = array(); |
23 |
|
24 |
/**
|
25 |
* The frameworks human readable name
|
26 |
* @access private
|
27 |
*/
|
28 |
private static $frameworkName = 'PCA Framework version 0.1'; |
29 |
|
30 |
/**
|
31 |
* The instance of the registry
|
32 |
* @access private
|
33 |
*/
|
34 |
private static $instance; |
35 |
|
36 |
/**
|
37 |
* Private constructor to prevent it being created directly
|
38 |
* @access private
|
39 |
*/
|
40 |
private function __construct() |
41 |
{
|
42 |
|
43 |
}
|
44 |
|
45 |
/**
|
46 |
* singleton method used to access the object
|
47 |
* @access public
|
48 |
* @return
|
49 |
*/
|
50 |
public static function singleton() |
51 |
{
|
52 |
if( !isset( self::$instance ) ) |
53 |
{
|
54 |
$obj = __CLASS__; |
55 |
self::$instance = new $obj; |
56 |
}
|
57 |
|
58 |
return self::$instance; |
59 |
}
|
60 |
|
61 |
/**
|
62 |
* prevent cloning of the object: issues an E_USER_ERROR if this is attempted
|
63 |
*/
|
64 |
public function __clone() |
65 |
{
|
66 |
trigger_error( 'Cloning the registry is not permitted', E_USER_ERROR ); |
67 |
}
|
68 |
|
69 |
/**
|
70 |
* Stores an object in the registry
|
71 |
* @param String $object the name of the object
|
72 |
* @param String $key the key for the array
|
73 |
* @return void
|
74 |
*/
|
75 |
public function storeObject( $object, $key ) |
76 |
{
|
77 |
require_once('objects/' . $object . '.class.php'); |
78 |
self::$objects[ $key ] = new $object( self::$instance ); |
79 |
}
|
80 |
|
81 |
/**
|
82 |
* Gets an object from the registry
|
83 |
* @param String $key the array key
|
84 |
* @return object
|
85 |
*/
|
86 |
public function getObject( $key ) |
87 |
{
|
88 |
if( is_object ( self::$objects[ $key ] ) ) |
89 |
{
|
90 |
return self::$objects[ $key ]; |
91 |
}
|
92 |
}
|
93 |
|
94 |
/**
|
95 |
* Stores settings in the registry
|
96 |
* @param String $data
|
97 |
* @param String $key the key for the array
|
98 |
* @return void
|
99 |
*/
|
100 |
public function storeSetting( $data, $key ) |
101 |
{
|
102 |
self::$settings[ $key ] = $data; |
103 |
|
104 |
|
105 |
}
|
106 |
|
107 |
/**
|
108 |
* Gets a setting from the registry
|
109 |
* @param String $key the key in the array
|
110 |
* @return void
|
111 |
*/
|
112 |
public function getSetting( $key ) |
113 |
{
|
114 |
return self::$settings[ $key ]; |
115 |
}
|
116 |
|
117 |
/**
|
118 |
* Gets the frameworks name
|
119 |
* @return String
|
120 |
*/
|
121 |
public function getFrameworkName() |
122 |
{
|
123 |
return self::$frameworkName; |
124 |
}
|
125 |
|
126 |
|
127 |
}
|
128 |
|
129 |
?>
|
Đối tượng Registry làm việc như thế nào?, Làm thế nào nó giữ cho việc lưu trữ các đối tượng của chúng ta một cách tốt nhất?
- Các đối tượng được lưu trữ trong một mãng.
- Khi một đối tượng mới được lưu trữ trong Registry, tập tin khai báo lớp của đối tượng đó cũng được bao gồm, đối tượng được khởi tạo và lưu trữ trong mãng.
- Các đối tượng sẽ được truy lục bằng cách truyền "khóa" của đối tượng đó khi gọi phương thức getObject.
Làm thế nào ngăn chặn việc sao chép một đối tượng đã được tạo và lưu trữ trong Registry?
- Xây dựng một hàm khởi dựng là riêng tư (private), sẽ ngăn chặn không cho phép tạo đối tượng một cách trực tiếp.
- Việc nhân bản đối tượng cũng sẽ gây nên lỗi.
- Nếu chúng ta muốn truy cập một đối tượng trong framework mà đối tượng đó không được phép truy cập trực tiếp thì chúng ta có thể sử dụng phương thức singleton (PCARegistry::singleto()) để lấy đối tượng đó trong Registry.
Bước 5: index.php
Sau khi đã hoàn thành cấu trúc cho framework, hãy xem xét làm thế nào chúng ta truy cập vào Registry, mọi công việc trong framework chúng ta đều phải thông qua tập tin index.php
Hiện nay, hầu hết các website đều sử dụng URL thân thiện, và cách đơn giản nhất để làm việc đó là phải chắc chắn rằng tất cả các yêu cầu truy cập đều phải thông qua tập tin index.php. Trong phần tiếp theo của loạt bài này, chúng ta sẽ tạo một tập tin .htaccess để chuyển các yêu cầu truy cập từ một url thân thiện sang một định dạng mà tập tin index.php của chúng ta có thể hiểu được.
Mã nguồn của index.php như bên dưới. Nó thì không nhiều tại thời điểm này, nhưng nó giúp ta có cái nhìn tổng quan về cách framework của chúng ta sẽ hoạt động.
1 |
|
2 |
<?php
|
3 |
/**
|
4 |
* PCAFramework
|
5 |
* Framework loader - acts as a single point of access to the Framework
|
6 |
*
|
7 |
* @version 0.1
|
8 |
* @author Michael Peacock
|
9 |
*/
|
10 |
|
11 |
// first and foremost, start our sessions
|
12 |
session_start(); |
13 |
|
14 |
// setup some definitions
|
15 |
// The applications root path, so we can easily get this path from files located in other folders
|
16 |
define( "APP_PATH", dirname( __FILE__ ) ."/" ); |
17 |
// We will use this to ensure scripts are not called from outside of the framework
|
18 |
define( "PCAFW", true ); |
19 |
|
20 |
/**
|
21 |
* Magic autoload function
|
22 |
* used to include the appropriate -controller- files when they are needed
|
23 |
* @param String the name of the class
|
24 |
*/
|
25 |
function __autoload( $class_name ) |
26 |
{
|
27 |
require_once('controllers/' . $class_name . '/' . $class_name . '.php' ); |
28 |
}
|
29 |
|
30 |
// require our registry
|
31 |
require_once('PCARegistry/pcaregistry.class.php'); |
32 |
$registry = PCARegistry::singleton(); |
33 |
|
34 |
// print out the frameworks name - just to check everything is working
|
35 |
print $registry->getFrameworkName(); |
36 |
|
37 |
exit(); |
38 |
|
39 |
?>
|
Xem qua tập tin index.php It:
- Gọi hàm start_session để chắc chắn rằng chúng ta có thể sử dụng session trong suốt framework của chúng ta (nó phải được gọi trước khi xuất nội dung ra màn hình).
- Định nghĩa đường dẫn tới tập tin hiện tại, như vậy chúng ta có thể tham khảo đến thư mục góc của framework từ nơi khác, nó cũng tạo ra một định nghĩa để chắc chắn rằng tất cả các tập tin của framework đều đang được gọi bên trong chính framework của, và một ai đó không thể gọi trực tiếp từ một nơi khác ngoài framework của chúng ta.
- Hàm autoload để xác định vị trí đặt của các lớp. Trong source code trên nó sẽ trỏ vào thư mục controllers, và đây là nơi đặt các tập tin xữ lý nghiệp vụ của chúng ta.
- Nó thêm vào lớp registry và điều này là cần thiết vì nó giúp tự động tìm kiếm, tự động nạp các lớp nằm ngoài thư mục controllers. Tiếp theo, khai báo biến $registry là một thể hiện của Registry.
- Cuối cúng, nó in ra tên của framework, để chỉ ra các hàm trong Registry đã làm việc.
Chúng ta có thể xem xét thêm, về Registry làm việc như thế nào trong framework của chúng ta bằng cách là thêm nhiều lớp giả vào. Với một lớp template được khai báo trong tập tin template.class.php và được đặt trong thư mục PCARegistry/objects, chúng ta có thêm một bằng chứng rằng Registry đã làm việc bằng cách thêm dòng code bên dưới vào tập tin index.php
Đặt dòng code này phía sau khai báo $registry
1 |
|
2 |
$registry->storeObject('template','template'); |
Nếu lớp template có một phương thức như generateOutput, chúng ta có thể gọi nó trong index.php như sau
1 |
|
2 |
$registry->getObject('template')->generateOutput(); |
Bây giờ, chúng ta đã có cấu trúc căn bản cho framework, chúng ta cũng có Registry để lưu trữ các hàm cốt lõi. Trong bài tiếp theo, chúng ta sẽ xem xét việc tạo một object và Registry sẽ lưu nó, bắt đầu với một tầng cơ sở dữ liệu trù tượng và quản lý an ninh.