Lập trình hướng đối tượng (OOP) là gì?
Lập trình hướng đối tượng, thường được gọi là OOP, một cách tiếp cận giúp bạn phát triển các ứng dụng phức tạp theo cách dễ dàng duy trì và có thể mở rộng trong thời gian dài. Trong thế giới của OOP, các thực thể trong thế giới thực như Person
, Car
hoặc Animal
được coi là object (đối tượng). Trong lập trình hướng đối tượng, bạn tương tác với ứng dụng của mình bằng cách sử dụng các object. Điều này trái ngược với lập trình thủ tục (procedural), nơi bạn chủ yếu tương tác với các hàm và biến toàn cục.
Trong OOP, có khái niệm về “class“, được sử dụng để mô hình hóa hoặc ánh xạ một thực thể trong thế giới thực sang một template dữ liệu (properties – các thuộc tính) và chức năng (methods – các phương thức). Một “object” là giá trị của một class và bạn có thể tạo nhiều giá trị của cùng một class. Ví dụ: có một class đơn lẻ Person
, nhưng nhiều object person có thể là các giá trị của class này – dan
, zainab
, hector
, v.v
Class định nghĩa các thuộc tính – property. Ví dụ: đối với class Person, chúng ta có thể có name
, age
và phoneNumber
. Sau đó, mỗi object person sẽ có giá trị riêng cho các thuộc tính đó.
Bạn cũng có thể định nghĩa các phương thức trong class cho phép bạn thao tác các giá trị của các thuộc tính object và thực hiện các thao tác trên các object. Ví dụ, bạn có thể định nghĩa một phương thức save
để lưu thông tin object vào cơ sở dữ liệu.
Class trong PHP là gì?
Một class là một khuôn mẫu đại diện cho một thực thể trong thế giới thực và nó định nghĩa các thuộc tính và phương thức của thực thể. Trong phần này, chúng tôi sẽ thảo luận về khung cơ bản một class PHP điển hình.
Cách tốt nhất để hiểu các khái niệm mới là qua ví dụ. Vì vậy, hãy xem class Employee
trong snippet sau, đại diện cho thực thể employee.
010203040506070809101112131415161718192021222324252627282930 | <?php class Employee { private $first_name ; private $last_name ; private $age ; public function __construct( $first_name , $last_name , $age ) { $this ->first_name = $first_name ; $this ->last_name = $last_name ; $this ->age = $age ; } public function getFirstName() { return $this ->first_name; } public function getLastName() { return $this ->last_name; } public function getAge() { return $this ->age; } } ?> |
Câu lệnh class Employee
trong dòng đầu tiên định nghĩa class Employee
. Sau đó, chúng ta tiếp tục khai báo các thuộc tính, hàm constructor và các phương thức class khác.Advertisement
Thuộc tính class trong PHP
Bạn có thể nghĩ các thuộc tính của class là các biến được sử dụng để chứa thông tin về object. Trong ví dụ trên, chúng tôi đã xác định ba thuộc tính của – first_name
, last_name
và age
. Trong đa số các trường hợp, các thuộc tính của class được truy xuất thông qua các object được khởi tạo.
Các thuộc tính này là private
, có nghĩa là chúng chỉ có thể được truy xuất từ bên trong class. Đây là mức truy xuất an toàn nhất cho các thuộc tính. Chúng tôi sẽ thảo luận về các cấp truy xuất khác nhau cho các thuộc tính và phương thức của class sau trong bài viết này.
Constructor cho các class PHP
Hàm constructor là một phương thức class đặc biệt tự động được gọi khi bạn khởi tạo một object. Chúng ta sẽ xem xét cách khởi tạo các object trong vài phần tiếp theo, nhưng bây giờ bạn chỉ cần biết rằng một hàm constructor được sử dụng để khởi tạo các thuộc tính object khi object được tạo ra.
Bạn có thể xác định hàm constructor bằng cách định nghĩa phương thức __construct
.
Các phương thức cho các class PHP
Chúng ta có thể nghĩ về các phương thức của class là các hàm thực hiện các hành động cụ thể được liên kết với các object. Trong hầu hết các trường hợp, chúng được sử dụng để truy xuất và thao tác các thuộc tính object và thực hiện các hoạt động liên quan.
Trong ví dụ trên, chúng tôi đã xác định phương thức getLastName
, nó trả về last name được liên kết với object.
Vì vậy, một giới thiệu ngắn gọn về cấu trúc class trong PHP. Trong phần tiếp theo, chúng tôi sẽ xem cách khởi tạo các object của class Employee
.
Một object trong PHP là gì?
Trong phần trước, chúng ta đã thảo luận về cấu trúc cơ bản của một class trong PHP. Bây giờ, khi bạn muốn sử dụng một class, bạn cần khởi tạo nó và kết quả cuối cùng là một object. Vì vậy, chúng ta có thể nghĩ về một class như một bản thiết kế và một object là một thứ thực tế mà bạn có thể làm việc với.
Trong ngữ cảnh của class Employee
mà chúng ta vừa tạo trong phần trước, hãy xem cách khởi tạo một object của class đó.
1234567 | <?php $objEmployee = new Employee( 'Bob' , 'Smith' , 30); echo $objEmployee ->getFirstName(); // print 'Bob' echo $objEmployee ->getLastName(); // prints 'Smith' echo $objEmployee ->getAge(); // prints '30' ?> |
Bạn cần sử dụng từ khóa new
khi bạn muốn khởi tạo một object của bất kỳ class nào cùng với tên class của nó và bạn sẽ nhận lại một giá trị object mới của class đó.
Nếu một class đã định nghĩa phương thức __construct
và nó yêu cầu các đối số, bạn cần truyền các đối số đó khi bạn khởi tạo một object. Trong trường hợp của chúng tôi, hàm constructor của class Employee
yêu cầu ba đối số và do đó chúng tôi đã vượt qua những đối số này khi chúng tôi tạo object $objEmployee
. Như chúng ta đã thảo luận trước đó, phương thức __construct
được gọi tự động khi object được khởi tạo.
Tiếp theo, chúng tôi đã gọi các phương thức class trên object $objEmployee
để in thông tin được khởi tạo trong quá trình tạo object. Tất nhiên, bạn có thể tạo nhiều object của cùng một class, như được hiển thị trong đoạn code sau.
01020304050607080910111213 | <?php $objEmployeeOne = new Employee( 'Bob' , 'Smith' , 30); echo $objEmployeeOne ->getFirstName(); // prints 'Bob' echo $objEmployeeOne ->getLastName(); // prints 'Smith' echo $objEmployeeOne ->getAge(); // prints '30' $objEmployeeTwo = new Employee( 'John' , 'Smith' , 34); echo $objEmployeeTwo ->getFirstName(); // prints 'John' echo $objEmployeeTwo ->getLastName(); // prints 'Smith' echo $objEmployeeTwo ->getAge(); // prints '34' ?> |
Hình ảnh sau đây là biểu diễn hình ảnh của class Employee và một số trường hợp của nó.
Nói một cách đơn giản, một class là một bản thiết kế mà bạn có thể sử dụng để tạo các object có cấu trúc.
Encapsulation (tính đóng gói)
Trong phần trước, chúng ta đã thảo luận về cách khởi tạo các object của class Employee
. Thật thú vị khi lưu ý rằng chính object $objEmployee
kết hợp các thuộc tính và phương thức của class. Nói cách khác, object này ẩn đi những chi tiết đó từ phần còn lại của chương trình. Trong thế giới OOP, điều này được gọi là encapsulation (đóng gói dữ liệu).
Đóng gói là một khía cạnh quan trọng của OOP cho phép bạn hạn chế quyền truy xuất vào các thuộc tính hoặc phương thức nhất định của object. Và điều đó đưa chúng ta đến một chủ đề khác để thảo luận: access level – mức độ truy xuất.
Access Levels (mức độ truy xuất)
Khi bạn định nghĩa một thuộc tính hoặc một phương thức trong một class, bạn có thể khai báo nó có một trong ba cấp truy xuất này, public
, private
hoặc protected
.
Public Access
Khi bạn khai báo một thuộc tính hoặc một phương thức là public, nó có thể được truy xuất từ bất cứ đâu bên ngoài class. Giá trị của một thuộc tính public có thể được sửa đổi từ bất cứ nơi nào trong code của bạn.
Hãy xem xét một ví dụ để hiểu mức độ truy xuất public.
010203040506070809101112131415 | <?php class Person { public $name ; public function getName() { return $this ->name; } } $person = new Person(); $person ->name = 'Bob Smith' ; echo $person ->getName(); // prints 'Bob Smith' ?> |
Như bạn có thể thấy trong ví dụ trên, chúng tôi đã khai báo thuộc tính name
là public. Do đó, bạn có thể đặt nó từ bất kỳ đâu ngoài class, như đã thực hiện ở đây.
Private Access
Khi bạn khai báo một thuộc tính hoặc một phương thức là private
, nó chỉ có thể được truy xuất từ bên trong class. Điều này có nghĩa là bạn cần xác định các phương thức getter và setter để lấy và xét giá trị của thuộc tính đó.
Một lần nữa, hãy xem lại ví dụ trước để hiểu mức độ truy xuất riêng.
010203040506070809101112131415161718192021 | <?php class Person { private $name ; public function getName() { return $this ->name; } public function setName( $name ) { $this ->name = $name ; } } $person = new Person(); $person ->name = 'Bob Smith' ; // Throws an error $person ->setName( 'Bob Smith' ); echo $person ->getName(); // prints 'Bob Smith' ?> |
Nếu bạn thử truy xuất một tài sản private bên ngoài class, nó sẽ gây ra lỗi nghiêm trọng Cannot access private property Person::$name
. Vì vậy, bạn cần xét giá trị của thuộc tính private bằng phương thức setter, như chúng ta đã sử dụng phương thức setName
.
Có nhiều lý do giải thích bạn có thể muốn làm cho một tài sản private. Ví dụ, có lẽ nên thực hiện một số hành động (cập nhật cơ sở dữ liệu, giả sử hoặc hiển thị lại một template) nếu thuộc tính đó thay đổi. Trong trường hợp đó, bạn có thể định nghĩa một phương thức setter và xử lý bất kỳ logic đặc biệt nào khi thuộc tính được thay đổi.
Protected Access
Cuối cùng, khi bạn khai báo một thuộc tính hoặc một phương thức là protected
, nó có thể được truy xuất bởi cùng một class đã định nghĩa nó và các class kế thừa class. Chúng ta sẽ thảo luận về kế thừa trong phần tiếp theo, vì vậy chúng ta sẽ quay lại cấp độ truy xuất protected sau đó.
Inheritance – kế thừa
Inheritance là một khía cạnh quan trọng của mô hình lập trình hướng đối tượng, cho phép bạn kế thừa các thuộc tính và phương thức của các class khác bằng cách mở rộng chúng. Lớp được kế thừa được gọi là parent class và class kế thừa class khác được gọi là child class. Khi bạn khởi tạo một object của child class, nó cũng thừa hưởng các thuộc tính và phương thức của parent class.
Chúng ta hãy nhìn vào ảnh chụp màn hình sau đây để hiểu khái niệm inheritance
Trong ví dụ trên, class Person là parent class và class Employee mở rộng hoặc kế thừa class Person và do đó được gọi là child class.
Chúng ta hãy thử xem xét một ví dụ thực tế để hiểu cách thức hoạt động của nó.
Điều quan trọng cần lưu ý ở đây là class Employee
đã sử dụng từ khóa extends
để kế thừa class Person
. Bây giờ, class Employee
có thể truy xuất tất cả các thuộc tính và phương thức của class Person
được khai báo là public hoặc protected. (Nó không thể truy xuất các thành viên được khai báo là private).
Trong ví dụ trên, object $employee
có thể truy xuất các phương thức getName
và setName
được định nghĩa trong class Person
khi được khai báo là public.
Tiếp theo, chúng tôi đã truy xuất phương thức callToProtectedNameAndAge
bằng phương thức getNameAndAge
được xác định trong class Employee
, vì nó được khai báo là protected. Cuối cùng, object $employee
không thể truy xuất phương thức callToPrivateNameAndAge
của class Person
vì nó được khai báo là private.
Mặt khác, bạn có thể sử dụng object $employee
để đặt thuộc tính age
của class Person
, như chúng ta đã làm trong phương thức setAge
được định nghĩa trong class Employee
, vì thuộc tính age
được khai báo là được bảo vệ.
Vì vậy, đó là một giới thiệu ngắn gọn về thừa kế. Nó giúp bạn giảm trùng lặp code, và do đó khuyến khích khả năng sử dụng lại code.
Polymorphism
Polymorphism là một khái niệm quan trọng khác trong thế giới lập trình hướng đối tượng, đề cập đến khả năng xử lý các object khác nhau dựa trên các loại dữ liệu của chúng.
Ví dụ, trong tình hướng thừa kế, nếu child class muốn thay đổi hành vi của phương thức của parent class, nó có thể override phương thức đó. Đây được gọi là phương thức override. Hãy nhanh chóng xem qua một ví dụ thực tế để hiểu khái niệm về phương thức override.
0102030405060708091011121314151617181920212223 | <?php class Message { public function formatMessage( $message ) { return printf( "<i>%s</i>" , $message ); } } class BoldMessage extends Message { public function formatMessage( $message ) { return printf( "<b>%s</b>" , $message ); } } $message = new Message(); $message ->formatMessage( 'Hello World' ); // prints '<i>Hello World</i>' $message = new BoldMessage(); $message ->formatMessage( 'Hello World' ); // prints '<b>Hello World</b>' ?> |
Như bạn có thể thấy, chúng tôi đã thay đổi hành vi của phương thức formatMessage
bằng cách override nó trong class BoldMessage
. Điều quan trọng là một thông điệp được định dạng khác nhau dựa trên loại object, cho dù đó là một giá trị của parent class hay child class.
(Một số ngôn ngữ hướng đối tượng cũng có một kiểu overload phương thức cho phép bạn định nghĩa nhiều phương thức của class có cùng tên nhưng số lượng đối số khác nhau. Điều này không được hỗ trợ trực tiếp trong PHP, nhưng có một số cách giải quyết để đạt được chức năng tương tự).
Tổng kết
Lập trình hướng đối tượng là một chủ đề lớn và chúng ta chỉ ra mặt nổi của sự phức tạp của nó. Tôi hy vọng rằng hướng dẫn này đã giúp bạn bắt đầu với những điều cơ bản của OOP và thúc đẩy bạn tiếp tục và tìm hiểu các chủ đề OOP nâng cao hơn.