Trait ها و Composition در PHP

۱۴۰۵/۰۸/۱۳ | چهارشنبه، ۱۳ آبان
دوره آموزشی ویژه 4 اپیزود اول تمام دوره های آموزشی ویدیویی رایگان میباشد دانلود رایگان

دورهٔ جامع CSS از صفر

آموزش CSS از صفر در ۲۲ ویدیو: مدل جعبه، انتخاب‌گر، فلکس‌باکس، گرید، واکنش‌گرایی، متغیرها، انیمیشن و معماری، تا پروژهٔ کامل صفحهٔ محصول؛ کد کنار خروجی ...

مدرس دوره : تیم 22 اپیزود ویدیویی 03 ساعت و 33 دقیقه و 59 ثانیه آموزش ویدیویی
متن پرونده شماره 242 - پی اچ پی
Trait و Composition
محصول اورجینال INZIP
قالب وردپرس باریستا مخصوص کافه تم نسکافه ای روشن (دو زبانه)

قالب وردپرس باریستا مخصوص کافه تم نسکافه ای روشن (دو زبانه)

دانلود پوسته وردپرس باریستا؛ قالب کافیشاپ، رُستری قهوه و فروشگاه قهوه دوزبانه با منوی رومیزی، رزرو آنلاین میز با کد پیامکی و ووکامرس. طراحی اختصاصی inzip.ir

تحویل آنی آپدیت رایگان بدون قفل لایسنس پشتیبانی واقعی
۳,۹۹۰,۰۰۰ تومان ۲,۹۶۰,۰۰۰ تومان
بازدید و دانلود آنی
٪۲۶
تخفیف ویژه
سود شما
۱,۰۳۰,۰۰۰ تومان

Trait ها و Composition در PHP

PHP از وراثت چندگانه کلاس‌ها پشتیبانی نمی‌کند. برای حل این محدودیت، Trait معرفی شد. همچنین اصل Composition over Inheritance یکی از اصول مهم طراحی شیءگرا است.

Trait چیست؟

Trait مکانیزمی برای استفاده مجدد از کد در کلاس‌های مختلف است که با کلمه کلیدی trait تعریف می‌شود:

<?php
trait SayHello {
    public function sayHello(): void {
        echo "سلام! من {$this->name} هستم
";
    }
    
    public function sayGoodbye(): void {
        echo "خداحافظ!
";
    }
}

trait HasTimestamps {
    private ?DateTime $createdAt = null;
    private ?DateTime $updatedAt = null;
    
    public function touch(): void {
        $this->updatedAt = new DateTime();
        if ($this->createdAt === null) {
            $this->createdAt = new DateTime();
        }
    }
    
    public function getCreatedAt(): ?DateTime {
        return $this->createdAt;
    }
}

class User {
    use SayHello, HasTimestamps;
    
    public function __construct(public string $name) {
        $this->touch();
    }
}

$user = new User("علی");
$user->sayHello();
echo $user->getCreatedAt()->format('Y-m-d H:i:s');
?>

ترکیب Trait ها

Trait ها می‌توانند از یکدیگر استفاده کنند:

<?php
trait LoggerTrait {
    public function log(string $message): void {
        echo "[" . date('H:i:s') . "] $message
";
    }
}

trait EventTrait {
    use LoggerTrait;
    
    private array $listeners = [];
    
    public function on(string $event, callable $callback): void {
        $this->listeners[$event][] = $callback;
    }
    
    public function emit(string $event, mixed $data = null): void {
        $this->log("رویداد: $event");
        foreach ($this->listeners[$event] ?? [] as $cb) {
            $cb($data);
        }
    }
}

class OrderService {
    use EventTrait;
    
    public function placeOrder(): void {
        $this->emit('order.placed', ['id' => 123]);
    }
}
?>

حل تداخل Trait ها

وقتی دو Trait متد هم‌نام دارند، باید از insteadof و as استفاده کرد:

<?php
trait A {
    public function hello() { echo "A"; }
}

trait B {
    public function hello() { echo "B"; }
}

class MyClass {
    use A, B {
        A::hello insteadof B;
        B::hello as helloB; // تغییر نام
    }
}

$obj = new MyClass();
$obj->hello();   // A
$obj->helloB();  // B
?>

Trait با ویژگی‌های Abstract

<?php
trait AbstractMethod {
    abstract public function getName(): string;
    
    public function printName(): void {
        echo "Name: " . $this->getName();
    }
}

class Product {
    use AbstractMethod;
    
    public function __construct(private string $name) {}
    
    public function getName(): string {
        return $this->name;
    }
}
?>

اصل Composition over Inheritance

به جای ارث‌بری، از ترکیب اشیاء استفاده کنیم:

<?php
// ❌ وراثت - انعطاف کم
class Bird {
    public function fly() { /* ... */ }
    public function swim() { /* ... */ }
}

class Penguin extends Bird {
    // پنگوئن نمی‌تواند پرواز کند!
    // باید متد fly را override کنیم
}

// ✅ Composition - انعطاف بالا
interface FlyBehavior {
    public function fly(): void;
}

interface SwimBehavior {
    public function swim(): void;
}

class FlyWithWings implements FlyBehavior {
    public function fly(): void { echo "پرواز با بال
"; }
}

class FlyNoWay implements FlyBehavior {
    public function fly(): void { echo "نمی‌تواند پرواز کند
"; }
}

class SwimFast implements SwimBehavior {
    public function swim(): void { echo "شنای سریع
"; }
}

class Duck {
    public function __construct(
        private FlyBehavior $flyBehavior,
        private SwimBehavior $swimBehavior
    ) {}
    
    public function performFly(): void {
        $this->flyBehavior->fly();
    }
    
    public function performSwim(): void {
        $this->swimBehavior->swim();
    }
    
    public function setFlyBehavior(FlyBehavior $fb): void {
        $this->flyBehavior = $fb;
    }
}

$duck = new Duck(new FlyWithWings(), new SwimFast());
$duck->performFly();  // پرواز با بال

$duck->setFlyBehavior(new FlyNoWay());
$duck->performFly();  // نمی‌تواند پرواز کند
?>

Dependency Injection (تزریق وابستگی)

یکی از مهم‌ترین الگوهای Composition:

<?php
interface Mailer {
    public function send(string $to, string $subject, string $body): void;
}

class SmtpMailer implements Mailer {
    public function send(string $to, string $subject, string $body): void {
        // ارسال از طریق SMTP
    }
}

class UserService {
    public function __construct(private Mailer $mailer) {}
    
    public function register(string $email): void {
        // ثبت‌نام
        $this->mailer->send(
            $email,
            'خوش آمدید',
            'ثبت‌نام شما با موفقیت انجام شد'
        );
    }
}

// استفاده
$service = new UserService(new SmtpMailer());
$service->register("user@example.com");
?>

Service Container (مفهوم)

<?php
class Container {
    private array $bindings = [];
    
    public function bind(string $abstract, callable $concrete): void {
        $this->bindings[$abstract] = $concrete;
    }
    
    public function make(string $abstract): mixed {
        if (!isset($this->bindings[$abstract])) {
            throw new Exception("سرویس $abstract ثبت نشده");
        }
        return call_user_func($this->bindings[$abstract], $this);
    }
}

$container = new Container();
$container->bind(Mailer::class, fn() => new SmtpMailer());
$container->bind(UserService::class, fn($c) => new UserService($c->make(Mailer::class)));

$service = $container->make(UserService::class);
?>

مقایسه نهایی

معیارInheritanceComposition
انعطاف‌پذیریکمبالا
پیچیدگیافزایش با عمقخطی
تست‌پذیریسخت‌ترآسان‌تر
استفاده مجددسلسله‌مراتبیآزادانه
زمان مناسبرابطه "is-a"رابطه "has-a"

نتیجه‌گیری

Trait ها ابزار خوبی برای استفاده مجدد از کد هستند اما نباید جایگزین طراحی خوب شوند. اصل Composition over Inheritance یکی از مهم‌ترین اصول SOLID است که در پروژه‌های بزرگ حتماً باید رعایت شود.

برچسب‌های این مقاله
  • Trait PHP
  • Composition
  • dependency injection
  • service container
  • وراثت چندگانه
٪۴۱
دوره اختصاصی INZIP

دورهٔ جامع HTML از صفر

آموزش حرفه ای HTML از صفر در ۱۶ ویدیو: سند، متن، لینک، تصویر، جدول، فرم، معنایی‌سازی، دسترس‌پذیری و سئو، تا پروژهٔ کامل صفحهٔ فروشگاه محصول.

تماشای آنلاین + دانلود دسترسی آنی و همیشگی به‌روزرسانی رایگان کیفیت Full HD
۹۹۰,۰۰۰ تومان ۵۹۰,۰۰۰ تومان سود شما ۴۰۰,۰۰۰ تومان
مشاهده سریال