PHP là ngôn ngữ chỉ hỗ trợ đơn kế thừa trong hướng đối tượng thế nên bạn muốn sử dụng lại source code một cách nhiều lần là rất khó khăn. Và để khắc phục điều đó thì từ PHP 5.4 trở lên, PHP đã hỗ trợ chúng ta Traits. Một khái niệm được dùng rất là nhiều trong các framework PHP hiện nay, điển hình là Laravel.
Vì Kiến thức xoay quanh Traits khá là dài nên mình sẽ chia làm 2 phần:
- Traits trong PHP.
- Traits trong PHP (phần 2).
1, Traits là gì?
- Traits là một module giúp cho chúng ta có thể sử dụng lại các phương thức được khai báo trong trait vào các class khác nhau một cách đơn giản hơn là kế thừa như trước.
-Các đặc điểm của Traits:
- Traits có chức năng gom lại các phương thức và thuộc tính mà chúng ta muốn sử dụng lại nhiều lần.
- Traits như một abstract class ( đều không thể khởi tạo được) nhưng không hoàn toàn giống nhau.
- Các phương thức trong Traits có thể bị override lại trong class sử dụng nó.
-Ưu điểm của Traits:
- Giảm việc lặp code đáp ứng được nguyên tắc(DRY - Don't Repeat Yoursefl).
- Khắc phục được điểm yếu đơn kế thừa của PHP.
-Nhược điểm của Traits: Nhược điểm duy nhất mà mình thấy được khi sử dụng traits đó là sẽ gây khó khăn có chúng ta đọc được các phương thức từ một class có sử dụng traits
2, Khai báo Traits.
-Để khai báo một trait trong PHP các bạn sử dụng cú pháp:
trait Name
{
//code
}
Trong đó: Name là tên của trait các bạn muốn đặt.
VD1: Khai báo một trait SetGetName
có hai phương thức setName()
và getName()
.
<?php
trait SetGetName
{
// private $name;
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
-Và với Trait bạn cũng hoàn toàn sử dụng được namespace nhé.
VD2: Khai báo một trait SetGetAge
có hai phương thức setAge()
và getAge()
và namespace là SetGetAge
luôn.
<?php
namespace SetGetAge;
trait SetGetAge
{
public function setAge($age)
{
$this->age = $age;
}
public function getAge()
{
return $this->age;
}
}
4, Sử dụng Trait trong class.
-Để sử dụng trait trong class thì các bạn chỉ cần sử dụng cú pháp:
class ClassName
{
use TraitName;
//code
}
Trong đó:
- ClassName là class mà bạn muốn sử dụng trait.
- TraitName là tên traits mà bạn muốn sử dụng.
VD: Mình sẽ gọi 2 trait ở trên vào trong class ConNguoi và đồng thời khởi tạo luôn.
<?php
// Nhúng 2 file chứa trait
include 'SetGetName.php';
include 'SetGetAge.php';
//khai báo class ConNguoi
class ConNguoi
{
private $name;
private $age;
//gọi trait SetGetName
use SetGetName;
//gọi trait SetGetAge
use SetGetAge\SetGetAge;
}
//khởi tạo đối tượng.
$connguoi = new ConNguoi();
// set name;
$connguoi->setName('Vũ Thanh Tài');
// get name;
echo $connguoi->getName();
//Tạo khoảng trắng cho dễ phân biệt
echo '<br/>';
// set age
$connguoi->setAge(22);
//get age
echo $connguoi->getAge();
//Kết quả chương trình trả về
//Vũ Thanh Tài
//22
-Hoặc bạn cũng có thể gọi namespace của trait và sử dụng nhiều trait bằng use như sau:
<?php
// Nhúng 2 file chứa trait
include 'SetGetName.php';
include 'SetGetAge.php';
//use namespace
use SetGetAge\SetGetAge;
//khai báo class ConNguoi
class ConNguoi
{
private $name;
private $age;
//gọi trait SetGetName
use SetGetName;
//gọi trait SetGetAge
use SetGetAge;
}
//khởi tạo đối tượng.
$connguoi = new ConNguoi();
// set name;
$connguoi->setName('Vũ Thanh Tài');
// get name;
echo $connguoi->getName();
//Tạo khoảng trắng cho dễ phân biệt
echo '<br/>';
// set age
$connguoi->setAge(22);
//get age
echo $connguoi->getAge();
//Kết quả chương trình trả về
//Vũ Thanh Tài
//22
5, Trait lồng.
-Cũng như các cấu trúc điều khiển hay vòng lặp thì bạn cũng có thể sử dụng trait lồng nhau.
VD:
trait A
{
//
}
trait B
{
use A;
//
}
-Lúc này khi bạn gọi trait B là bạn cũng có thể sử dụng đầy đủ chức năng của trait A.
6, Ưu tiên phương thức trong traits.
-Giả sử như bạn có hai trait như sau:
//trait SetGetName
trait SetGetName
{
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getAll()
{
return $this->getName();
}
}
//trait SetGetAge
trait SetGetAge
{
public function setAge($age)
{
$this->age = $age;
}
public function getAge()
{
return $this->age;
}
public function getAll()
{
return $this->getAge();
}
}
-Bây giờ nếu như bạn gọi 2 trait trên vào trong một class thì lập tức chương trình lỗi ngay.
VD:
<?php
//trait SetGetName
trait SetGetName
{
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getAll()
{
return $this->getName();
}
}
//trait SetGetAge
trait SetGetAge
{
public function setAge($age)
{
$this->age = $age;
}
public function getAge()
{
return $this->age;
}
public function getAll()
{
return $this->getAge();
}
}
class ConNguoi
{
private $name;
private $age;
//gọi trait
use SetGetName, SetGetAge;
}
//chương trình báo lỗi.
//Fatal error: Trait method getAll has not been applied,
//because there are collisions with other trait methods on ConNguoi
-Giờ đây sẽ có 2 giải pháp để sử lỗi trên như sau:
Cách 1: Là bạn sẽ phải override lại phương thức trùng tên đó ở trong class sử dụng.
VD:
class ConNguoi
{
private $name;
private $age;
//gọi trait
use SetGetName, SetGetAge;
public function getAll()
{
return $this->getName();
}
}
Cách 2: Xử dụng insteadof
để xét độ ưu tiên cho phương thức bạn muốn sử dụng.
VD:
class ConNguoi
{
private $name;
private $age;
//gọi trait
use SetGetName, SetGetAge {
//ưu tiên sử dụng phương thức getall của trait SetGetAge
SetGetAge::getAll insteadof SetGetName;
}
}
7, Lời kết.
- Như vậy phần này mình đã giới thiệu xong đến mọi người kiến thức cơ bản của traits trong PHP rồi, phần sau chúng ta sẽ tìm hiểu tiếp các vấn đề về thành phần tĩnh và phương thức trừu tượng xoay quanh Traits.
Đăng ký nhận tin.
Chúng tôi chỉ gửi tối đa 2 lần trên 1 tháng. Tuyên bố không spam mail!
Tài xem lại phần
-Hoặc bạn cũng có thể gọi namespace của trait và sử dụng nhiều trait bằng use như sau:
đang dùng include chứ không phải use ;
với mình thắc mắc hơi ngu tí là php hỗ trợ đơn kế thừa, nên mới có traits, vậy sao không dùng implement ?
cám ơn Tài
Hỏi liều
7 năm trước
Chào bạn,
Cám ơn bạn đã đặt câu hỏi, mình xin trả lời các câu hỏi của bạn như sau:
1, Do PHP là một ngôn ngữ kịch bản và mặc định nó không có cơ chế autoload, lên khi bạn muốn sử dụng một module, file nào nó thì bạn cần phải embed nó vào file hiện tại, trong ví dụ bạn thắc mắc thì để sử dụng được trait thì trước hết cần phải embed nó vào file hiện tại đã, sau đó mới dùng use được.
2, Implements giúp cho chúng ta thực hiện lại các khuân mẫu mà interface đã định ra, và interface thì chỉ có thể khai báo phương thức chứ không được viết code cho phương thức đó, còn trait thì có thể.
Bạn có thể tham khảo: toidicode.com/104
Cám ơn bạn!
Vũ Thanh Tài
7 năm trước
cám ơn tác giả (y)
Hỏi liều
7 năm trước
Cho mình hỏi code minh họa trong bài là dùng IDE gì thế, nhìn màu có vẻ đỡ mỏi mắt.
Diamond
6 năm trước
Bạn muốn màu tương tự có thể sử dụng material theme:
https://github.com/equinusocio/material-theme
Vũ Thanh Tài
6 năm trước
Sử dụng chứ không phải Xử dụng
Trait chứ không phải Traits
Minh Vũ
6 năm trước
Traits ở đây nói đến nhiều mẫu nên là traits.
Vũ Thanh Tài
6 năm trước
cho em hỏi khi sử dụng trait thì n bị nhảy lên đầu làm sao để khắc phục
ví dụ em muốn in ra hello word thì em dùng echo 'hello'. sayword();
nhưng n lại in ra word hello
hiền
6 năm trước
Bạn có thể cho mình xem code của bạn được không?
Vũ Thanh Tài
6 năm trước