Hướng dẫn dùng mapclass trong PHP

Khi mới làm quen với lập trình chúng ta thường bắt đầu với các ngôn ngữ như C, Pascal là những ngôn ngữ lập trình cấu trúc với việc thực hiện mã lệnh tuần tự kèm theo các câu lệnh điều kiện và các vòng lặp. Kiểu lập trình này giúp chúng ta có thể nhanh chóng tiếp cận và thực hành, nhưng với các dự án dần dà nó có những yếu điểm trong phát triển phần mềm.

1. Lập trình hướng đối tượng là gì?

OOP viết tắt của Object-Oriented Programming - Lập trình hướng đối tượng ra đời giải quyết các vấn đề mà lập trình truyền thống gặp phải. Lập trình hướng đối tượng không chỉ đơn giản là các cú pháp, câu lệnh mới mà còn là một cách tư duy mới khi giải quyết một vấn đề. Thực tế khi làm một việc gì đó, chúng ta sẽ quan tâm đến hai điều: vật bị tác động và hành động. Với lập trình cũng vậy, nếu chúng ta tập trung vào hành động thì đó là lập trình hướng thủ tục còn nếu tập trung vào các vật thể thì đó là lập trình hướng đối tượng. Với cả hai cách giải quyết vấn đề, đều cho chúng ta một kết quả như nhau, chỉ có một điều khác nhau là cách chúng ta tập trung vào cái gì?

Trong lập trình hướng đối tượng OOP, có hai thuật ngữ rất quan trọng là lớp [class] và đối tượng [object]. Class là định nghĩa chung cho một vật, để dễ tưởng tượng bạn có thể nghĩ đến class là một bản thiết kế trong khi đó đối tượng là một thực hiện cụ thể của bản thiết kế. Ví dụ, object là một ngôi nhà cụ thể thì class là bản thiết kế ngôi nhà đó. Lập trình hướng đối tượng là cách bạn thiết kế các class và sau đó thực hiện chúng thành các đối tượng trong chương trình khi cần. Lập trình hướng đối tượng có 4 tính chất chính:

  • Tính kế thừa
  • Tính trìu tượng
  • Tính đóng gói
  • Tính đa hình

Với OOP, ứng dụng ra thành các phần nhỏ, ví dụ website có thể làm nhiều thứ như tương tác với database, quản lý form, gửi email, tạo mã HTML… mỗi thứ đó có thể là một module hay một class. Bằng cách tách biệt các thành phần không liên quan, các class sẽ độc lập, dễ bảo trì và cập nhật, debug lỗi cũng vì thế đơn giản hơn.

Một vấn đề cũng hay gặp với những người mới làm quen với OOP là khi chia nhỏ các thành phần, các lớp được định nghĩa quá rộng, ví dụ thay vì định nghĩa một class để tương tác với một cơ sở dữ liệu MySQL, bạn tạo ra một class tương tác với cơ sở dữ liệu không xác định, class này hoạt động như một lớp database chung chung, nhưng tính năng của nó lại hướng về một thứ cố định.

Trong OOP, các class là các thành phần riêng biệt được đóng kín và ẩn đi cách thức hoạt động bên trong nó, một thuộc tính của lớp có thể làm việc gì đó nếu bạn cần làm mà bạn không biết cách nó hoàn thành như thế nào. Bên cạnh những ưu điểm, OOP cũng có những vấn đề của nó, OOP không phải là cách tốt hơn trong lập trình, nó đơn giản chỉ là một hướng đi khác trong giải quyết vấn đề.

Trong một số trường hợp nó tốt hơn, nhưng cũng có những trường hợp OOP là tồi hơn. Có nhiều lập trình viên thấy rằng lập trình hướng đối tượng sử dụng các đối tượng có thể kém hiệu quả hơn phương pháp lập trình hướng thủ tục. Hiệu năng giữa hai phương pháp là không đáng kể trong nhiều trường hợp, nhưng có những nguy cơ tiềm ẩn từ những việc khác. Những thông tin trên đây có thể làm cho bạn hơi mung lung, khó hiểu về lập trình hướng đối tượng, nhưng bạn hãy bình tĩnh và chỉ cần một câu ngắn gọn để nhớ về OOP:

Lập trình hướng đối tượng chỉ đơn giản là cách tư duy khác để giải quyết vấn đề mà trong đó chúng ta tập trung vào các đối tượng thay vì tập trung vào hành động.

2. Các khái niệm cơ bản trong lập trình hướng đối tượng

2.1 Class - Bản thiết kế

Trong lập trình hướng đối tượng, chúng ta sẽ tập trung vào các vật [danh từ] ví dụ như ngôi nhà, xe ô tô... và với một vật thì bản thiết kế hay mô hình trìu tượng là cái đầu tiên nghĩ đến và class chính là cái chúng ta đang nói đến. Một class User có thể lưu trữ các thông tin như tên, id, địa chỉ email… Các chức năng của User có thể là đăng nhập, đăng xuất, thay đổi mật khẩu… Class được định nghĩa với từ khóa class và theo sau là tên của class, tên class không được đặt trùng với các từ khóa được sử dụng bởi hệ thống, thông thường tên class tuân thủ theo kiểu Pascal Case [chữ cái đầu viết hoa]. Sau tên lớp, các định nghĩa về lớp được đặt trong hai dấu ngoặc nhọn:

class ClassName {
   // Nội dung của lớp
}

Các lớp có thể chứa các biến [variable] và hàm [function], trong lập trình hướng đối tượng, biến trong class được gọi là thuộc tính [property] và hàm được gọi là phương thức [method]. Các thuộc tính và phương thức là thành phần của class.

class ClassName {
  function functionName[] {
    // Code của phương thức
  }
}

Phương thức được định nghĩa trong một class giống như một hàm ở ngoài lớp, chúng có thể có các tham số, giá trị mặc định và trả về giá trị khi kết thúc… Thuộc tính trong các lớp khác biệt một chút so với các biến ở ngoài lớp. Đầu tiên, các thuộc tính phải được khai báo với các từ khóa để biết phạm vi truy nhập như public, private, protected. Các giá trị này chỉ có ý nghĩa khi thực hiện thừa kế các class, chúng ta sẽ nói đến chi tiết trong các phần tiếp theo:

class ClassName {
  public $var1, $var2;
  function functionName[] {
    // Code của phương thức
  }
}

Trong khai báo một class, các thuộc tính được khai báo đầu tiên, sau đó đến các phương thức trong class. Một sự khác biệt nữa giữa thuộc tính [property] và biến thông thường [variable] là thuộc tính được khởi tạo với một tập giá trị thuần túy chứ không được khởi tạo với giá trị là kết quả của một biểu thức.

class GoodClass {
  public $var1 = 123;
  public $var2 = 'string';
  public $var3 = array[1, 2, 3];
}
class BadClass {
  // Khai báo thuộc tính với kết quả của biểu thức là lỗi ngay
  public $today = get_date[];
  public $square = $num * $num;
}

Một số chú ý là thuộc tính không nhất thiết phải có giá trị khởi tạo, chú ý nữa các đoạn code khác ngoài việc khai báo thuộc tính phải được thực hiện ở trong phương thức, không thể thực hiện các câu lệnh bên ngoài một phương thức.

class BadClass {
  public $num = 2;
  public $square;
  $square = $num * $num; // Không được viết code ngoài phương thức.
}

Trên đây chúng ta đã có được các kiến thức về class, một khái niệm cơ sở quan trọng của OOP. Các đoạn code trong lý thuyết chỉ để minh họa, chúng ta cần có các ví dụ cụ thể hơn giúp hiểu rõ lý thuyết đưa ra. Một cách học lập trình tốt là học đến đâu thực hành đến đấy. Trong loạt bài về "Lập trình hướng đối tượng trong PHP", chúng ta cũng sẽ làm như vậy, mỗi phần lý thuyết sẽ được tiếp theo bởi các ví dụ. Phần tiếp theo đây, chúng ta cùng tạo ra một môi trường thực hành.

2.2 Các bước cài đặt môi trường thực hành lập trình hướng đối tượng trong PHP

Bước 1: Tải và cài đặt XAMPP, đây là một phần mềm tổng hợp bên trong đã có sẵn PHP, Apache [máy chủ web].

Bước 2: Tạo thư mục C:/xampp/htdocs/OOP để chứa các code thực hành.

Bước 3 [tùy chọn]: Ở bước 2 là chúng ta đã có thể truy cập các file php từ trình duyệt với đường dẫn //localhost/OOP, tuy nhiên nếu bạn muốn truy nhập theo kiểu domain ảo dạng //oop.dev chúng ta thực hiện mở file hosts nằm trong C:\Windows\System32\drivers\etc và thêm vào:

# Copyright [c] 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments [such as these] may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
127.0.0.1       localhost
127.0.0.1       oop.dev

Sau đó, mở file httpd-vhosts.conf trong thư mục C:\xampp\apache\conf\extra để map domain ảo này với thư mục mã nguồn:


    DocumentRoot "C:/xampp/htdocs/OOP"
    ServerName oop.dev

Khởi động lại Apache trong XAMPP Control Panel là bạn đã có thể sử dụng được tên miền ảo //oop.dev cho các ví dụ thực hành. Ok, chúng ta đã cài đặt xong môi trường và bắt tay tạo ra một ví dụ về class. Ví dụ HelloWorld để khởi đầu, nhiệm vụ chỉ đơn giản là in ra màn một câu chào bằng các thứ tiếng khác nhau. Trong lập trình hướng đối tượng, mỗi class có thể được lưu trên một file khác nhau hoặc đưa toàn bộ các code vào một file giống lập trình thủ tục cũng được, chúng ta sẽ tạo ra một file HelloWorld.php nằm trong thư mục C:/xampp/htdocs/OOP với nội dung sau:



Để sử dụng được class HelloWorld được khai báo trong file OOP/HelloWorld.php chúng ta cần câu lệnh require trước khi tạo ra một đối tượng từ class này. Tiếp theo, với đối tượng $obj được tạo ra từ class HelloWorld, chúng ta gọi phương thức sayHello[] để in câu chào ra màn hình, nếu không truyền tham số nó sẽ lấy giá trị mặc định là tiếng Anh để in ra lời chào, các lời chào tiếp theo được in ra bằng tiếng Việt, tiếng Trung Quốc và tiếng Pháp. Kết thúc, khi không sử dụng đến đối tượng này nữa chúng ta thực xóa chúng đi. Kết quả là bạn truy nhập vào //oop.dev/hello.php sẽ được như sau:

2.4 Biến $this

Class HelloWorld đã làm được một số việc và là một ví dụ dễ hiểu để khởi đầu, class này có duy nhất một phương thức và không có bất kỳ thuộc tính nào. Như đã trình bày trong phần trước, khái niệm về thuộc tính:

  • Thuộc tính là một biến.
  • Thuộc tính phải khai báo phạm vi truy nhập với các từ khóa public, protected, private.
  • Nếu thuộc tính có khởi tạo giá trị thì phải là giá trị thuần túy, không được là kết quả của biểu thức.

Trên đây là các nguyên tắc khi định nghĩa một thuộc tính, khi sử dụng thuộc tính cần thêm một chút thông tin. Khi truy nhập vào thuộc tính của class chúng ta cần thông qua toán tử đối tượng ->

$object->propertyName;

Có một vấn đề là chúng ta muốn truy cập thuộc tính trong chính class đó. Bạn không thể sử dụng:

class BadClass {
  public $var;
  function do[] {
    // Sử dụng biến kiểu này không đúng.
    print $var;
  }
}

Phương thức do[] không thể truy xuất thuộc tính $var, giải pháp là sử dụng một biến đặc biệt là $this. Biến $this trong một class tham chiếu đến thực thể hiện tại của class. Trong một phương thức, bạn có thể tham chiếu đến thực thể của class và các thuộc tính bằng cách sử dụng cú pháp $this->attributeName. Trong phần thực hành với biến $this, chúng ta đến với một ví dụ tạo ra một class hình chữ nhật với các thuộc tính chiều rộng, chiều cao và các phương thức như tính chu vi, diện tích... Tạo file Rectangle.php trong thư mục OOP.



Khi tạo ra đối tượng từ class Rectangle, chúng ta có thể thiết lập giá trị chiều rộng và chiều cao cho đối tượng, khi đó biến $this tham chiếu đến đối tượng này. Kiểm tra xem ví dụ hoạt động như thế nào trong đường dẫn //oop.dev/rectangle\_calculate.php

3. Các phương thức được xây dựng sẵn trong Class

Trong class có sẵn một số phương thức [còn gọi là magic method] giúp cho việc sử dụng class thuận tiện hơn, có một số phương thức liên quan đến việc khởi tạo và hủy bỏ một đối tượng, cũng có một số phương thức giúp làm việc với các đối tượng như tạo một bản sao đối tượng, nhân bản đối tượng... Các phương thức này có một số khác biệt với phương thức chuẩn:

  • Tên luôn bắt đầu với hai dấu gạch dưới __ và tên phương thức được cố định bởi hệ thống.
  • Thực hiện một số công việc đặc biệt tại những thời điểm khác nhau trong vòng đời của đối tượng.

3.1 Phương thức khởi tạo __construct[]

Phương thức khởi tạo [contructor] là một phương thức đặc biệt, tên phương thức luôn là __construct[]. Phương thức này được gọi mỗi khi một đối tượng được tạo ra từ class. Phương thức này không trả về giá trị, do đó không sử dụng câu lệnh return trong __construct[]. Khai báo phương thức khởi tạo như sau:

class ClassName {
  public $var;
  function __construct[] {
    // Các công việc cần thực hiện khi khởi tạo đối tượng
  }
}

Phương thức khởi tạo thực hiện các công việc cần thiết để khởi tạo đối tượng như kết nối với cơ sở dữ liệu, thiết lập cookie hoặc khởi tạo các giá trị ban đầu. Phương thức khởi tạo cũng có thể có tham số và giá trị các tham số này được truyền vào khi tạo đối tượng.

class User {
  function __construct[$id] {
    // Các công việc cần thực hiện khi khởi tạo đối tượng
  }
}
$me = new User[1234];

Trong ví dụ Rectangle.php ở phần 1.3, chúng ta sẽ tạo ra một hàm khởi tạo và trong đó thiết lập luôn giá trị chiều rộng, chiều cao của đối tượng hình chữ nhật.



Chạy lại đường dẫn //oop.dev/rectangle\_calculate.php chúng ta thấy hàm khởi tạo __contruct đã được sử dụng để thiết lập kích thước hình chữ nhật khi tạo đối tượng.

3.2 Phương thức hủy __destruct[]

Phương thức hủy __destruct[] ngược với phương thức khởi tạo __contruct[], nó được gọi đến khi đối tượng bị hủy bỏ.

$obj = new ClassName[];
unset[$obj]; // Gọi đến phương thức hủy __destruct[] và thực hiện hủy bỏ đối tượng

Hoặc nó được gọi khi đoạn mã được thực thi xong [tại thời điểm này PHP giải phóng các biến khỏi bộ nhớ]. Khai báo phương thức hủy như sau:

class ClassName {
  // Khai báo các thuộc tính và phương thức
  function __destruct[] {
    // Các công việc cần thực hiện khi hủy bỏ đối tượng
  }
}

Hàm hủy __destruct cũng là các công việc kết thúc vòng đời của một đối tượng, ví dụ tiếp theo này chúng ta sẽ cùng tìm hiểu vòng đời của một đối tượng. Tạo ra file object_lifecycle.php với nội dung như sau:




   
   Object lifecyle
   


    

Bạn thấy đấy, trong các sự kiện xảy ra trong vòng đời của một đối tượng, chúng ta đều có thể thực hiện một việc gì đấy. Chú ý, ở đây chúng ta chủ động thực hiện xóa đối tượng khi sử dụng xong bằng lệnh unset[$demo], trong trường hợp không xóa đối tượng, ứng dụng sẽ tự động xóa đối tượng khi kết thúc thực thi đoạn mã. Nếu bạn bỏ dòng unset[$demo] thì thứ tự của sự kiện thứ 5 và thứ 6 ở trên sẽ đảo cho nhau.

3.3 Phương thức __get[], __set[] và __isset[] làm việc với thuộc tính trong class

Với toán tử đối tượng -> chúng ta có thể truy nhập một thuộc tính của đối tượng, tuy nhiên nếu thuộc tính chưa được khai báo trong class thì làm thế nào? Phương thức __get và __set[] giúp chúng ta khai báo các giá trị thích hợp cho các thuộc tính không được khai báo của một class. Chúng ta cùng xem ví dụ sau:

Chủ Đề