---
description: https://toidicode.com/traits-trong-php-108.html
---

# \[TRAIT] Traits trong PHP (ok)

C:\xampp\htdocs\php\a.php

```
<?php
trait SetGetName {
  private $name;
  public function setName($name) {
    $this->name = $name;
  }
  public function getName() {
    return $this->name;
  }
}
```

C:\xampp\htdocs\php\c.php

```
<?php
namespace SetGetAge;
trait SetGetAge {
  public function setAge($age) {
    $this->age = $age;
  }
  public function getAge() {
    return $this->age;
  }
}
```

C:\xampp\htdocs\php\b.php

```
<?php
// Nhúng 2 file chứa trait
include 'a.php';
include 'c.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
```

## 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](https://toidicode.com/tu-hoc-codeigniter-16) hiện nay, điển hình là [Laravel](https://toidicode.com/laraveltu-hoc-laravel-14).

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)](https://toidicode.com/traits-trong-php-phan-2-109.html).

Mục Lục

* [1, Traits là gì?](https://toidicode.com/traits-trong-php-108.html#load-h2-0)
* [2, Khai báo Traits.](https://toidicode.com/traits-trong-php-108.html#load-h2-1)
* [4, Sử dụng Trait trong class.](https://toidicode.com/traits-trong-php-108.html#load-h2-2)
* [5, Trait lồng.](https://toidicode.com/traits-trong-php-108.html#load-h2-3)
* [6, Ưu tiên phương thức trong traits.](https://toidicode.com/traits-trong-php-108.html#load-h2-4)
* [7, Lời kết.](https://toidicode.com/traits-trong-php-108.html#load-h2-5)

### 1, Traits là gì? <a href="#load-h2-0" id="load-h2-0"></a>

\- **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**:&#x20;

* 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. <a href="#load-h2-1" id="load-h2-1"></a>

-Để 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. <a href="#load-h2-2" id="load-h2-2"></a>

-Để 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. <a href="#load-h2-3" id="load-h2-3"></a>

-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. <a href="#load-h2-4" id="load-h2-4"></a>

-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. <a href="#load-h2-5" id="load-h2-5"></a>

\- 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](https://toidicode.com/traits-trong-php-phan-2-109.html) 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.
