Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A trait is a compiler-assisted mechanism for horizontal code reuse in PHP, designed to circumvent the limitations of single inheritance. It enables the composition of methods, properties, and constants into independent classes residing in disparate class hierarchies without establishing an inheritance relationship. At compile time, the PHP engine effectively copies the trait’s members into the consuming class.

Declaration and Consumption

Traits are declared using the trait keyword and imported into a class using the use keyword within the class body.
trait ArrayConvertible {
    public function toArray(): array {
        return get_object_vars($this);
    }
}

class User {
    use ArrayConvertible;
    
    public string $name = 'Admin';
}

Method Precedence

PHP enforces a strict precedence order when resolving method names to prevent ambiguity between traits, base classes, and the consuming class:
  1. Consuming Class: Methods defined in the current class override trait methods.
  2. Trait: Trait methods override inherited methods from a parent class.
  3. Parent Class: Inherited methods have the lowest priority.
class Base {
    public function output(): void { echo "Base"; }
}

trait OutputTrait {
    public function output(): void { echo "Trait"; }
}

class Child extends Base {
    use OutputTrait;
    
    // If defined, this overrides the trait.
    // public function output(): void { echo "Child"; } 
}

$obj = new Child();
$obj->output(); // Outputs: "Trait"

Conflict Resolution

When a class consumes multiple traits that share identical method names, a fatal error occurs unless the conflict is explicitly resolved. Because PHP does not support method overloading by signature, a collision occurs purely based on the method name, regardless of the parameters. PHP provides the insteadof and as operators to resolve these conflicts.
  • insteadof: Instructs the compiler which trait’s method to prioritize.
  • as: Creates an alias for a method, allowing the overridden method to still be invoked.
trait Reader {
    public function execute(): void { echo "Reading"; }
}

trait Writer {
    public function execute(): void { echo "Writing"; }
}

class FileHandler {
    use Reader, Writer {
        Writer::execute insteadof Reader;
        Reader::execute as readExecute;
    }
}

Visibility Modification

The as operator can also mutate the access modifier (visibility) of a trait method within the consuming class.
trait InternalLogic {
    private function calculate(): int { return 42; }
}

class API {
    use InternalLogic {
        calculate as public; // Exposes the private trait method as public
        // calculate as public getCalculation; // Can alias and change visibility simultaneously
    }
}

Abstract Methods

Traits can declare abstract methods to enforce a contract on the consuming class. The class utilizing the trait must implement these abstract methods with a compatible signature.
trait Stateful {
    abstract public function getState(): string;

    public function validateState(): bool {
        return $this->getState() === 'active';
    }
}

class Process {
    use Stateful;

    public function getState(): string {
        return 'active';
    }
}

Properties and Constants

Traits can define properties and, as of PHP 8.2, constants. If a trait defines a property, the consuming class cannot define a property with the same name unless it has the exact same visibility, type, and initial value (otherwise, a fatal error is thrown).
trait Configurable {
    public const MAX_RETRIES = 3; // Requires PHP 8.2+
    protected array $config = [];
}

class Service {
    use Configurable;
    
    // Fatal Error: Cannot redefine property $config with a different default value
    // protected array $config = ['timeout' => 10]; 
}

Static Properties

When a trait defines a static property, each consuming class receives its own independent copy of that static property. The state of the static property is not shared across all classes that use the trait; it is bound to the specific class into which the trait is composed.
trait Counter {
    public static int $count = 0;

    public static function increment(): void {
        self::$count++;
    }
}

class Order {
    use Counter;
}

class Invoice {
    use Counter;
}

Order::increment();
Order::increment();
Invoice::increment();

echo Order::$count;   // Outputs: 2
echo Invoice::$count; // Outputs: 1

Trait Composition

Traits can consume other traits, allowing for granular composition of behaviors before they are applied to a concrete class.
trait Authenticated {
    public function checkAuth(): bool { return true; }
}

trait Audited {
    public function logAction(): void {}
}

trait SecureEndpoint {
    use Authenticated, Audited;
}
Master PHP with Deep Grasping Methodology!Learn More