Toidicode.com

Toidicode.com

BASIC TO ADVANCE

Bài 12: Traits trong PHP

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:

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()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()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!

Vũ Thanh Tài

About author
The best way to learn is to share
Xem tất cả bài đăng

9 Comments

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

Bình luận

Captcha