While looking through a PHP codebase, I was greeted by a familiar keyword, traits. Rust uses traits to define behaviour and to constraint generic types to specific traits, similar to how interface based design works in Go.

PHP traits carry a different meaning. In PHP, traits provide horizontal reuse for classes. This is very different from trait bounds in Rust, which focus on type contracts rather than shared implementations.

Here’s an example of trait bound:

trait Printable {}

struct Post;
struct Comment;

impl Printable for Post {}
impl Printable for Comment {}

// T must implement Printable
fn print<T: Printable(_item: T) {
    println!("I can print!");
}

fn main() {
    print(Post);
    print(Comment);
}

PHP also supports using multiple traits in one class, which might look like it conflicts with the single inheritance rule. It does not. Instead, it offers a clean way to add focused pieces of logic to a class through composition rather than pushing that logic into a parent class that all children must inherit.

So when should you use traits? Use them when you want to reuse behaviour across different classes without creating a hierarchy. Traits fit well when:

  • several classes need the same method implementations
  • the shared behaviour does not justify a parent class
  • you want to keep your inheritance path open
  • you want to mix in small reusable pieces of logic

A trait example:

trait Timestamps {
    public function touch() {
        $this->updatedAt = time();
    }
}

class Post {
    use Timestamps;
    public $updatedAt;
}

class Comment {
    use Timestamps;
    public $updatedAt;
}