Mở đầu
Lập trình hướng đối tượng (gọi tắt là OOP
– object-oriented programming) là một kĩ thuật lập trình hỗ trợ công nghệ đối tượng. Nếu như trước kia là các kiểu lập trình hướng thủ tục, hướng module,.. thì giờ đây thế giới đang ưu về sử dụng hướng đối tượng.Nếu như trước đây chúng ta lập trình với hướng thủ tục thì sẽ chia thành các hàm để xử lý, thì giờ đây khi sử dụng hướng đối tượng thì chúng ta sẽ chia ra thành các đối tượng để xử lý.
Bài viết dưới đây sẽ tập trung giải đáp các vấn đề sau:
- Các đặc điểm cơ bản của lập trình hướng đối tượng. Chúng được thể hiện như thế nào trong PHP.
- Sự khác biệt giữa Abstract Class và Interface.
- Thế nào là một hàm static. Phân biệt cách dùng từ khoá static::method() với self::method().
- Thế nào là Trait.
- Thế nào là Namespaces.
1. Các đặc điểm cơ bản của lập trình hướng đối tượng. Chúng được thể hiện như thế nào trong PHP.
Lập trình hướng đối tượng (OOP
) có 4 đặc trưng cơ bản:
- Tính đóng gói (Encapsulation)
- Tính kế thừa (Inheritance)
- Tính đa hình (Polymorphism)
- Tính trừu tượng (Abstraction)
Tính đóng gói : Tính đóng gói được thể hiện qua việc các thuộc tính, phương thức được che giấu trong một lớp (class
), nhằm mục đích kiểm soát quyền sử dụng, truy cập đến các thuộc tính, phương thức.
Tính đóng gói trong PHP được thể hiện thông qua việc sử dụng các từ khóa public
, private
, protected
:
public
: Cho phép sử dụng thuộc tính và phương thức củaclass
ở phạm vi trong, ngoàiclass
, cácclass
con kế thừa từ đó đều có thể linh động sử dụng lại.private
: Chỉ cho phép sử dụng trong phạm viclass
đó.protected
: Cho phép sử dụng ở phạm vi trongclass
cha và cácclass
kế thừa từclass
cha.
Tính kế thừa: được thể hiện qua việc các class
con kế thừa lại các phương thức, thuộc tính của class
cha.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token keyword">class</span> <span class="token class-name">Cha</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token variable">$quoctinh</span> <span class="token operator">=</span> <span class="token single-quoted-string string">'Viet Nam'</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"Noi tieng Viet Nam"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Con</span> <span class="token keyword">extends</span> <span class="token class-name">Cha</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">parent</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">new</span> <span class="token class-name">Con</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">=</span><span class="token operator">></span> Noi tieng Viet Nam |
Tính trừu tượng : trong lập trình hướng đối tượng giúp giảm sự phức tạp thông qua việc tập trung vào các đặc điểm trọng yếu hơn là đi sâu vào chi tiết.
Như vậy khi tương tác với đối tượng chỉ cần quan tâm đến các thuộc tính, phương thức cần thiết. Chi tiết về nội dung không cần chú ý đến.
PHP có abstract class
và interface
để trừu tượng hóa các đối tượng.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">interface</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token keyword">implements</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"Go go go"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Tính đa hình: thể hiện qua việc các class
con có thể viết lại các phương thức từ class
cha, thông qua việc extends
và implements
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <span class="token keyword">interface</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token keyword">implements</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"Go go go"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Cat</span> <span class="token keyword">implements</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"Meowwww"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">new</span> <span class="token class-name">Dog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">=</span><span class="token operator">></span> Go go go <span class="token keyword">new</span> <span class="token class-name">Cat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">=</span><span class="token operator">></span> Meowwww |
2. Sự khác biệt giữa Abstract Class và Interface.
Ở phần 1, chúng ta có nhắc tới 2 khái niệm abstract class
và interface
. Interface
và Abstract class
là 2 khái niệm cơ bản trong lập trình OOP. Nhưng phân lớn mọi người cảm thấy mơ hồ và lẫn lộn 2 khái niệm này.
Abstract class
: là một class
trừu tượng cho tất cả các class có cùng bản chất. Do đó mỗi lớp dẫn xuất (lớp con) chỉ có thể kế thừa từ một lớp trừu tượng. Bên cạnh đó nó không cho phép tạo instance
, nghĩa là sẽ không thể tạo được các đối tượng thuộc lớp đó.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token double-quoted-string string">"Noi..."</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">new</span> <span class="token class-name">Dog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// => Báo lỗi</span> <span class="token keyword">class</span> <span class="token class-name">Cat</span> <span class="token keyword">extends</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">new</span> <span class="token class-name">Cat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// => Noi...</span> |
Interface
: Lớp này được xem như một mặt nạ cho tất cả các Class cùng cách thức hoạt động nhưng có thể khác nhau về bản chất. Từ đó lớp con dẫn xuất có thể kế thừa từ nhiều lớp Interface
để bổ sung đầy đủ cách thức hoạt động của mình (đa kế thừa – Multiple inheritance).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <span class="token keyword">interface</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">method_a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">B</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">method_b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token keyword">implements</span> <span class="token class-name">A</span><span class="token punctuation">,</span> <span class="token constant">B</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">noi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">method_b</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// TODO: Implement method_b() method.</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">method_a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// TODO: Implement method_a() method.</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
3. Thế nào là một hàm static. Phân biệt cách dùng từ khoá static::method() với self::method().
Thế nào là một hàm static?: Hàm static
là hàm có thể được gọi mà không cần một đối tượng của class
đó. Static
nó hoạt động như một biến toàn cục dù cho nó có được xử lý ở trong bất kỳ một file nào đi nữa (trong cùng một chương trình) thì nó đều lưu lại giá trị cuối cùng mà nó được thực hiện vào trong lớp.
1 2 3 4 5 | <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function">staticMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//TODO</span> <span class="token punctuation">}</span> |
Việc thực thi hàm static trong class có thể thực hiện bằng lệnh:
static::staticMethod()
,self::staticMethod()
hoặc$this->staticMethod()
, trong đóself
vàstatic
là đại diện củaclass
, còn$this
là đại diện củaobject
. Trong phương thứcstatic
không thể gọi phương thức hoặc thuộc tínhnon-static
. Nhưng phương thứcnon-static
có thể gọi phương thức hoặc thuộc tínhstatic
. Bởi vì có thể hiểu đơn giản như sau:
- Phương thức
static
có thể gọi ngay cả khi chưa khởi tạoobject
, do đó nếu phương thứcstatic
gọi đến một phương thứcnon-static
thì khi chưa khởi tạoobject
, sẽ không có biến$this
(là đại diện củaobject
) để gọi đến phương thứcnon-static
.- Đương nhiên phương thức
non-static
luôn luôn có thể gọi đến phương thứcstatic
vì phương thứcstatic
đã tồn tại ngay từ khi chạy chương trình, khiobject
chưa được khởi tạo.
Phân biệt cách dùng từ khoá static::method()
với self::method()
:
static
: đại diện cho chính đối tượng đang gọi đến phương thựcself
: đại diện cho chính đối tượng khai báo nó.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function">getSeflObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">self</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">function</span> <span class="token function">getStaticObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">static</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Girl</span> <span class="token keyword">extends</span> <span class="token class-name">Person</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">echo</span> <span class="token function">get_class</span><span class="token punctuation">(</span>Girl<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">getSeflObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//Person</span> <span class="token keyword">echo</span> <span class="token function">get_class</span><span class="token punctuation">(</span>Girl<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">getStaticObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//Girl</span> |
4. Thế nào là Trait.
Traits
hiểu đơn giản là một nhóm các methods mà bạn muốn include nó trong một class khác. Một Trait
giống vớiabstract class
không thể khởi tạo trên chính nó. Trait
giảm bớt hạn chế của việc đơn kế thừa
, cho phép chúng ta sử dụng lại một nhóm các phương thức trên class
.
Một Trait
đơn giản có thể là:
1 2 3 4 5 6 7 8 | <span class="token keyword">trait</span> Sharable <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">share</span><span class="token punctuation">(</span><span class="token variable">$item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token single-quoted-string string">'share this item'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Chúng ta có thể sử dụng nó trong các class
khác nhau như sau:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">class</span> <span class="token class-name">Post</span> <span class="token punctuation">{</span> <span class="token keyword">use</span> <span class="token package">Sharable</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Comment</span> <span class="token punctuation">{</span> <span class="token keyword">use</span> <span class="token package">Sharable</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Như vậy, khi bạn khởi tạo các đối tượng từ class Post
, Comment
, đối tượng đó sẽ có sẵn phương thức share()
.
Chúng ta có thể sử dụng nhiều Trait
trong 1 class
.
5. Thế nào là Namespaces.
Namespace giúp tạo ra một không gian tên cho hàm và lớp trong lập trình nói chung và trong PHP nói riêng. Với PHP, Namespaces
được thiết kế để giải quyết hai vấn đề là tác giả của thư viện và các ứng dụng khi tái sử dụng lại các lớp và các hàm.
- Namespaces tránh việc tên hàm, tên lớp có thể trùng lặp, xung đột khi bạn tạo ra với các hàm, lớp, biến của PHP hay của bên thứ ba.
- Namespaces có khả năng tạo ra bí danh, rút ngắn cách đặt tên làm cho mã nguồn dễ đọc hiểu hơn.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">namespace</span> <span class="token package">AppControllers</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">NewsController</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token constant">__NAMESPACE__</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
PHP Namespaces
cung cấp cách để nhóm các class
, interface
, function
, constant
liên quan.
Kết luận
Qua bài viết, hy vọng các bạn đã hiểu được cơ bản về hướng đối tượng và việc thể hiện nó trong PHP, một vài khái niệm được sử dụng rộng rãi.