1. Traits trong PHP hướng đối tượng 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 traits vào các class khác nhau. Hay hiểu một cách đơn giản hơn nó là một cơ chế tái sử dụng code một cách đơn giản hơn là kế thừa như trước, giúp các phương thức có thể sử dụng trong nhiều lớp.

Một traits nhằm giảm hạn chế của sự đơn kế thừa bằng cách cho phép nhà phát triển sử dụng lại các bộ phương thức một cách tự do trong số một số lớp độc lập trong các hệ thống phân cấp lớp khác nhau.

Một traits tương tự như một lớp(class), nhưng chỉ nhằm mục đích nhóm chức năng lại một cách chi tiết và nhất quán hơn thôi đồng thời cho ta sử dụng lại nhiều lần. Traits thì cũng giống như một abstract class đều không thể khởi tạo được(nhưng không phải giống nhau hoàn toàn).

Traits có thể có các phương thức và phương thức trừu tượng để có thể sử dụng trong nhiều lớp và các phương thức có thể có bất kỳ chỉ định truy cập nào(public, private, protected).

2. Sự khác nhau giữa traits với abstract class và interface

2.1. Traits và abstract class

Traits khác với abstract class bởi vì chúng không phụ thuộc vào sự kế thừa.

Ví dụ như việc nếu Post và Comment class kế thừa một Abstract class. Chúng ta có thể muốn nhiều hơn việc chỉ share các post hay comment trên các mạng xã hội, vì vậy mà có lẽ chúng ta sẽ sử dụng một cây kế thừa phức tạp hơn:

class AbstractValidate extends AbstractCache {}
class AbstractSocial extends AbstractValidate {}
class Post extends AbstractSocial {}

Việc kế thừa phức tạp trên khá là khó chịu nhưng nó cũng thêm sự phiền phức là khi một đối tượng đơn giản không có cấu trúc kế thừa tương tự.

2.2. Traits và interface

Traits thì có đặc điểm khá là giống interface, cả 2 đều luôn đơn giản ngắn gọi và không sử dụng nhiều nếu không có một class thực tế được implements. Tuy nhiên sự khác biệt giữa chúng là interface là một giao ước rằng đối tượng này có thể thực hiện điều này, trong khi traits cho phép một đối tượng có khả năng thực hiện cái gì đó. Ví dụ:

// Interface
interface Sociable {

    public function like();
    public function share();

}

// Trait
trait Sharable {

    public function share($item)
    {
        // share this item
    }

}

// Class
class Post implements Sociable {

    use Sharable;

    public function like()
    {
        //
    }

}

Trong ví dụ này chúng ta có một interface Sociable cho đối tượng Post có thể like và share. Traits Sharable triển khai(implements) phương thức share() phương thức like() được triển khai trong lớp Post.

Vì vậy mà ta có thể gõ gợi ý đối tượng Post để thấy rằng nếu đó là Sociable(nó được implements Sociable interface) trong khi các traints được định nghĩa một phương thức tái sử dụng mà chúng ta có thể kết hợp trong các class tương tự khác.

$post = new Post;

if ($post instanceOf Sociable) {
    $post->share('hello world');
}

3. Ưu và nhược điểm của Traits trong PHP

Ưu điểm của việc sử dụng Trait đó là bạn giảm việc trùng lặp code trong khi không phải sử dụng đa kế thừa phức tạp mà không có ý nghĩa trong bối cảnh ứng dụng của bạn. Điều này cho phép bạn xác định Traits đơn giản rõ ràng súc tích và kết hợp nó trong những chức năng thích hợp.

Còn về nhược điểm của traits thì mình thấy như sau:

Traits tạo ra việc bạn có thể dễ viết các classe cồng kềnh và có quá nhiều chức năng. Một Trait bản chất là một cách để copy và paste code giữa các classes. Bởi có một cách đơn giản để thêm một nhóm các methods vào một class.

Một điểm khác nữa khi sử dụng Traits đó là không thể xem xét tất cả methods của một class khi nhìn vào source code cũng như method bị xung đột hay lặp logic.

Mình nghĩ rằng khi Traits được sử dụng đúng cách thì nó sẽ là một công cụ tuyệt vời cho việc xử lý của chúng ta. Tuy vậy, Traits cũng có thể trở thành vật chống lưng cho lập trình lười biếng (lazy programming). Bạn có thể giải quyết vấn đề ngay lập tức chỉ với việc thêm một trait. Thường thì Composition là cách tiếp cận tốt hơn kế thừa hoặc sử dụng một Trait.