DANH MỤC: PHP HƯỚNG ĐỐI TƯỢNG

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.

Nguồn: Toidicode.com

Thông tin tác giả

Vũ Thanh Tài

Vũ Thanh Tài

The best way to learn is to share

Hãy tham gia group facebook để cùng giao lưu chia sẻ kiến thức! Tham Gia