در پروژههای واقعی PHP معمولاً اتفاقی در سیستم رخ میدهد که بعد از آن باید چند عملیات مختلف انجام شود.
برای مثال تصور کنید کاربر جدیدی در سایت ثبتنام میکند. بعد از ثبتنام ممکن است بخواهیم:
- ایمیل خوشآمدگویی ارسال کنیم.
- اطلاعات کاربر را در سیستم CRM ثبت کنیم.
- یک لاگ ایجاد کنیم.
- پیامک ارسال کنیم.
- کاربر را عضو خبرنامه کنیم.
- یک اعلان داخل پنل ایجاد کنیم.
- اطلاعات ثبتنام را برای یک سرویس خارجی ارسال کنیم.
یک روش ساده این است که تمام این عملیات را مستقیماً داخل متد ثبتنام بنویسیم.
اما با بزرگتر شدن پروژه، این روش باعث افزایش وابستگی بین کلاسها میشود.
اینجاست که Observer Pattern در PHP میتواند راهحل مناسبی باشد.
Observer یک الگوی طراحی رفتاری است که اجازه میدهد یک شیء به نام Subject تغییر یا رخداد خاصی را اعلام کند و چند شیء دیگر به نام Observer به آن واکنش نشان دهند. این الگو یک رابطه یکبهچند ایجاد میکند و هدف آن کاهش وابستگی مستقیم بین این بخشهاست.
Observer Pattern چیست؟
Observer Pattern یا الگوی مشاهدهگر روشی برای ایجاد ارتباط بین یک شیء اصلی و چند شیء وابسته است.
در این الگو، یک شیء اصلی که معمولاً آن را Subject مینامیم، لیستی از Observerها را نگهداری میکند.
هر زمان وضعیت Subject تغییر کند یا رویداد مشخصی اتفاق بیفتد، Subject به Observerهای ثبتشده اطلاع میدهد.
ساختار کلی را میتوان اینطور تصور کرد:
Subject
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
Observer 1 Observer 2 Observer 3
│ │ │
▼ ▼ ▼
Email SMS Log
در این ساختار، Subject لازم نیست بداند هر Observer دقیقاً چه کاری انجام میدهد.
فقط میداند که Observer میتواند به تغییرات واکنش نشان دهد.
یک مثال ساده از دنیای واقعی
فرض کنید در یک فروشگاه اینترنتی، سفارش جدیدی ثبت میشود.
بعد از ثبت سفارش باید چند کار انجام شود:
- ارسال ایمیل برای مشتری
- ارسال پیامک
- ثبت لاگ
- اطلاع به انبار
- اطلاع به سیستم حسابداری
اگر همه این موارد را مستقیماً داخل کلاس OrderService قرار دهیم، کلاس به مرور بزرگ و وابسته میشود.
مثلاً:
<?php
final class OrderService
{
public function create(array $data): void
{
// ایجاد سفارش
$this->sendEmail();
$this->sendSms();
$this->updateInventory();
$this->createAccountingRecord();
$this->writeLog();
}
}
در ظاهر کد ساده است، اما مشکل زمانی شروع میشود که تعداد عملیات افزایش پیدا کند.
مثلاً چند ماه بعد بخواهیم:
- اطلاعات سفارش را به CRM بفرستیم.
- برای مدیر اعلان ایجاد کنیم.
- اطلاعات را به یک API خارجی ارسال کنیم.
- سیستم امتیازدهی مشتری را بهروزرسانی کنیم.
در این حالت OrderService به تعداد زیادی سرویس مختلف وابسته خواهد شد.
# مشکل Coupling چیست؟
یکی از مفاهیم مهم در طراحی نرمافزار، Coupling یا وابستگی بین بخشهای مختلف است.
اگر یک کلاس مستقیماً تعداد زیادی کلاس دیگر را صدا بزند، تغییر یک بخش میتواند روی بخشهای دیگر تأثیر بگذارد.
مثلاً:
<?php
final class RegisterUser
{
public function register(string $email): void
{
// ذخیره کاربر
$mailer = new Mailer();
$mailer->sendWelcome($email);
$sms = new SmsService();
$sms->sendWelcome($email);
$crm = new CrmService();
$crm->createCustomer($email);
$logger = new Logger();
$logger->info('User registered');
}
}
کلاس RegisterUser حالا مسئولیتهای زیادی دارد.
اگر سرویس SMS تغییر کند، ممکن است مجبور شویم همین کلاس را تغییر دهیم.
اگر CRM تغییر کند، دوباره همین کلاس باید تغییر کند.
اگر یک سرویس جدید اضافه شود، باز هم باید این کلاس را تغییر دهیم.
Observer Pattern تلاش میکند این وابستگی را کاهش دهد.
# ساختار Observer Pattern
Observer Pattern معمولاً شامل دو نقش اصلی است:
Subject
Subject همان شیء اصلی است که وضعیت یا رخداد آن برای سایر اشیا اهمیت دارد.
وظایف Subject معمولاً شامل موارد زیر است:
- نگهداری Observerها
- اضافه کردن Observer
- حذف Observer
- اطلاع دادن به Observerها
Observer
Observer شیئی است که منتظر رخداد یا تغییر در Subject است.
وقتی Subject تغییر میکند، Observer متوجه این تغییر شده و عملیات خودش را انجام میدهد.
# پیادهسازی Observer Pattern در PHP
بیایید ابتدا یک مثال ساده و قابل فهم بسازیم.
فرض کنید میخواهیم وقتی سفارش ثبت شد، چند Observer مطلع شوند.
ابتدا Interface مربوط به Observer را ایجاد میکنیم:
<?php
declare(strict_types=1);
interface OrderObserver
{
public function update(Order $order): void;
}
هر Observer باید متد update را داشته باشد.
حالا کلاس سفارش را میسازیم:
<?php
declare(strict_types=1);
final class Order
{
private array $observers = [];
public function attach(OrderObserver $observer): void
{
$this->observers[] = $observer;
}
public function detach(OrderObserver $observer): void
{
foreach ($this->observers as $key => $item) {
if ($item === $observer) {
unset($this->observers[$key]);
}
}
}
public function create(): void
{
echo "Order created\n";
$this->notify();
}
private function notify(): void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
حالا میتوانیم Observerهای مختلف ایجاد کنیم.
# ساخت Email Observer
<?php
declare(strict_types=1);
final class EmailOrderObserver implements OrderObserver
{
public function update(Order $order): void
{
echo "Order confirmation email sent.\n";
}
}
این Observer وظیفه ارسال ایمیل را بر عهده دارد.
# ساخت SMS Observer
<?php
declare(strict_types=1);
final class SmsOrderObserver implements OrderObserver
{
public function update(Order $order): void
{
echo "Order confirmation SMS sent.\n";
}
}
حالا یک Observer دیگر برای ثبت لاگ ایجاد میکنیم.
# ساخت Log Observer
<?php
declare(strict_types=1);
final class LogOrderObserver implements OrderObserver
{
public function update(Order $order): void
{
echo "Order activity logged.\n";
}
}
اکنون سه Observer داریم:
Order
│
├── EmailOrderObserver
│
├── SmsOrderObserver
│
└── LogOrderObserver
# استفاده از Observerها
حالا میتوانیم Observerها را به سفارش متصل کنیم:
<?php
$order = new Order();
$order->attach(
new EmailOrderObserver()
);
$order->attach(
new SmsOrderObserver()
);
$order->attach(
new LogOrderObserver()
);
$order->create();
وقتی create() اجرا شود، Subject تمام Observerهای ثبتشده را مطلع میکند.
خروجی میتواند چیزی شبیه این باشد:
Order created
Order confirmation email sent.
Order confirmation SMS sent.
Order activity logged.
نکته مهم این است که Order لازم نیست بداند Email Observer دقیقاً چگونه ایمیل ارسال میکند.
همین موضوع باعث کاهش وابستگی میشود.
# متد attach چیست؟
متد attach برای ثبت یک Observer استفاده میشود.
مثلاً:
$order->attach(
new EmailOrderObserver()
);
با این کار Email Observer در لیست Observerهای Subject قرار میگیرد.
# متد detach چیست؟
اگر بخواهیم یک Observer دیگر به تغییرات Subject واکنش نشان ندهد، میتوانیم آن را حذف کنیم.
مثلاً:
$emailObserver = new EmailOrderObserver();
$order->attach($emailObserver);
$order->detach($emailObserver);
بعد از detach دیگر آن Observer هنگام notify اجرا نمیشود.
الگوی رایج Observer نیز معمولاً قابلیتهای ثبت و حذف Observerها را در Subject در نظر میگیرد.
# متد notify چیست؟
notify وظیفه دارد تمام Observerهای ثبتشده را اجرا کند.
در سادهترین حالت:
private function notify(): void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
بنابراین جریان اجرا اینگونه است:
Event happens
↓
Subject
↓
notify()
↓
Observer 1
Observer 2
Observer 3
# استفاده از SplSubject و SplObserver در PHP
یکی از نکات مهم در مورد Observer Pattern این است که PHP خودش Interfaceهای SplSubject و SplObserver را در اختیار ما قرار میدهد.
این Interfaceها برای پیادهسازی ساختار استاندارد Observer کاربرد دارند.
SplSubject متدهای اصلی زیر را دارد:
attach()
detach()
notify()
و SplObserver متد زیر را تعریف میکند:
update()
بنابراین میتوانیم مثال قبلی را با امکانات داخلی PHP بازنویسی کنیم.
# پیادهسازی Observer با SplSubject
ابتدا Subject:
<?php
declare(strict_types=1);
use SplObjectStorage;
use SplObserver;
use SplSubject;
final class Order implements SplSubject
{
private SplObjectStorage $observers;
public function __construct()
{
$this->observers = new SplObjectStorage();
}
public function attach(SplObserver $observer): void
{
$this->observers->attach($observer);
}
public function detach(SplObserver $observer): void
{
$this->observers->detach($observer);
}
public function notify(): void
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function create(): void
{
echo "Order created.\n";
$this->notify();
}
}
در اینجا SplObjectStorage برای نگهداری مجموعهای از اشیای Observer استفاده شده است.
# ساخت Observer با SplObserver
<?php
declare(strict_types=1);
use SplObserver;
use SplSubject;
final class EmailObserver implements SplObserver
{
public function update(SplSubject $subject): void
{
echo "Email notification sent.\n";
}
}
Observer دیگری برای لاگ:
<?php
declare(strict_types=1);
use SplObserver;
use SplSubject;
final class LogObserver implements SplObserver
{
public function update(SplSubject $subject): void
{
echo "Order logged.\n";
}
}
حالا:
<?php
$order = new Order();
$order->attach(
new EmailObserver()
);
$order->attach(
new LogObserver()
);
$order->create();
این همان مفهوم اصلی Observer Pattern را با Interfaceهای استاندارد PHP پیادهسازی میکند.
# Observer Pattern در پروژههای واقعی چه کاربردی دارد؟
Observer فقط یک مثال آموزشی نیست و در سیستمهای واقعی کاربردهای زیادی دارد.
برای مثال:
ثبتنام کاربر
بعد از ثبتنام:
User Registered
│
├── Send Welcome Email
├── Send SMS
├── Create CRM Record
└── Write Log
ثبت سفارش
Order Created
│
├── Send Email
├── Update Inventory
├── Create Invoice
├── Notify Admin
└── Create Log
پرداخت موفق
Payment Successful
│
├── Activate Service
├── Send Receipt
├── Update Wallet
├── Notify User
└── Create Transaction Log
تغییر قیمت محصول
Product Price Changed
│
├── Update Cache
├── Notify Admin
├── Update Search Index
└── Write Audit Log
در تمام این موارد، یک رخداد میتواند چند واکنش مستقل داشته باشد.
# Observer Pattern و Publish/Subscribe
یکی از اصطلاحاتی که در بحث Observer زیاد میبینیم، Publish/Subscribe یا Pub/Sub است.
در این مدل:
- Publisher رخداد را منتشر میکند.
- Subscriber به رخداد گوش میدهد.
- Publisher لازم نیست بداند چه Subscriberهایی وجود دارند.
برای مثال:
Publisher
│
│ UserRegistered
▼
Event
│
├── Email Listener
├── SMS Listener
├── CRM Listener
└── Analytics Listener
این ساختار یکی از مفاهیم مهم معماری Event-Driven است.
# تفاوت Observer Pattern و Event System
Observer Pattern و سیستم Event/Listener بسیار به یکدیگر نزدیک هستند، اما دقیقاً یکی نیستند.
در Observer کلاس Subject معمولاً Observerهای خود را نگهداری میکند.
اما در یک Event Dispatcher، معمولاً یک سیستم مرکزی وظیفه مدیریت Eventها و Listenerها را بر عهده دارد.
مثلاً:
Event Dispatcher
│
├── Listener 1
├── Listener 2
└── Listener 3
در نتیجه Event Dispatcher را میتوان نوعی پیادهسازی گستردهتر و مرکزیتر از ایده Publish/Subscribe دانست.
# Observer Pattern در Laravel
اگر با Laravel کار کرده باشید، احتمالاً با مفاهیمی مانند:
- Event
- Listener
- Model Observer
آشنا هستید.
Laravel از معماری Event و Listener برای جدا کردن رخدادها از واکنشهای مربوط به آنها استفاده میکند.
برای مثال تصور کنید کاربری ثبتنام میکند.
بهجای اینکه داخل Controller تمام کارها را انجام دهیم:
<?php
public function register()
{
// Create user
// Send email
// Send SMS
// Create CRM record
// Log activity
}
میتوانیم یک Event ایجاد کنیم:
<?php
final class UserRegistered
{
public function __construct(
public readonly int $userId
) {
}
}
سپس Listenerهای مختلفی داشته باشیم:
UserRegistered
│
├── SendWelcomeEmail
├── SendWelcomeSms
├── CreateCrmCustomer
└── LogUserRegistration
در این حالت منطق ثبتنام از واکنشهای بعد از ثبتنام جدا میشود.
# مثال Laravel برای Event و Listener
فرض کنید کاربر ثبتنام شده است.
در سرویس ثبتنام:
<?php
use App\Events\UserRegistered;
event(
new UserRegistered($user->id)
);
حالا Listener مربوط به ارسال ایمیل میتواند مسئول این کار باشد:
<?php
namespace App\Listeners;
use App\Events\UserRegistered;
final class SendWelcomeEmail
{
public function handle(
UserRegistered $event
): void {
// Send welcome email
}
}
Listener دیگری میتواند SMS ارسال کند:
<?php
namespace App\Listeners;
use App\Events\UserRegistered;
final class SendWelcomeSms
{
public function handle(
UserRegistered $event
): void {
// Send SMS
}
}
مزیت اصلی این ساختار این است که کدی که کاربر را ثبت میکند، لازم نیست بداند بعد از ثبتنام دقیقاً چه اتفاقاتی رخ خواهد داد.
# Laravel Model Observer چیست؟
Laravel همچنین مفهوم Model Observer دارد.
Model Observer برای زمانی بسیار مفید است که بخواهیم نسبت به lifecycle یک مدل واکنش نشان دهیم.
مثلاً برای مدل Product میتوانیم به رخدادهایی مانند موارد زیر واکنش نشان دهیم:
- creating
- created
- updating
- updated
- deleting
- deleted
- restoring
- restored
مثلاً:
<?php
namespace App\Observers;
use App\Models\Product;
final class ProductObserver
{
public function created(Product $product): void
{
// Clear cache
// Update search index
// Write log
}
}
در این حالت تغییرات مربوط به مدل Product میتوانند واکنشهای مشخصی را فعال کنند.
# چه زمانی از Laravel Observer استفاده کنیم؟
Model Observer زمانی مناسب است که یک عملیات به lifecycle یک مدل وابسته باشد.
برای مثال:
Product Updated
↓
Clear Product Cache
یا:
Order Created
↓
Create Invoice
اما اگر یک فرآیند پیچیده کسبوکاری دارید که باید در نقاط مختلف سیستم منتشر شود، Event و Listener معمولاً انتخاب مناسبتری است.
# مزایای Observer Pattern
۱. کاهش وابستگی
Subject لازم نیست جزئیات Observerها را بداند.
این یکی از مهمترین مزایای این الگو است.
۲. امکان اضافه کردن واکنش جدید
فرض کنید بعد از ثبت سفارش فقط ایمیل و SMS داریم.
بعداً میتوانیم Observer دیگری اضافه کنیم:
$order->attach(
new AccountingObserver()
);
بدون اینکه منطق اصلی سفارش را تغییر دهیم.
۳. رعایت اصل Open/Closed
در بسیاری از سناریوها میتوان رفتار جدید را با اضافه کردن Observer جدید توسعه داد، بدون اینکه Subject اصلی را تغییر دهیم.
۴. جداسازی مسئولیتها
ارسال ایمیل، ارسال SMS، ثبت لاگ و بهروزرسانی CRM در کلاسهای جدا قرار میگیرند.
۵. قابلیت تست بهتر
هر Observer را میتوان مستقل تست کرد.
مثلاً:
$emailObserver = new EmailObserver();
و عملکرد آن را جداگانه تست کرد.
# معایب Observer Pattern
Observer نیز مانند هر Design Pattern دیگری هزینه و Trade-off دارد.
۱. پیچیده شدن جریان اجرای برنامه
ممکن است از داخل یک متد فقط این خط را ببینید:
$this->notify();
اما پشت آن پنج Observer اجرا شوند.
برای توسعهدهندهای که با پروژه آشنا نیست، پیدا کردن تمام اتفاقات ممکن است دشوار باشد.
۲. وابستگی پنهان
اگر تعداد Observerها زیاد شود، ممکن است رفتار سیستم در نگاه اول مشخص نباشد.
۳. مشکل در مدیریت خطا
اگر یکی از Observerها خطا ایجاد کند، باید مشخص باشد که:
- آیا Observerهای بعدی اجرا شوند؟
- آیا کل عملیات شکست بخورد؟
- آیا خطا Log شود؟
- آیا عملیات دوباره تلاش شود؟
این موضوع در سیستمهای حساس اهمیت زیادی دارد.
۴. مشکل عملیات سنگین
اگر Observer مستقیماً عملیات سنگینی مانند ارسال HTTP Request یا پردازش فایل بزرگ انجام دهد، ممکن است درخواست کاربر کند شود.
برای چنین عملیاتهایی معمولاً Queue انتخاب مناسبتری است.
# Observer و Queue چه تفاوتی دارند؟
این دو مفهوم را نباید با هم اشتباه بگیریم.
Observer مشخص میکند:
> وقتی اتفاقی افتاد، چه بخشهایی باید مطلع شوند؟
Queue مشخص میکند:
> این عملیات چه زمانی و در چه فرآیندی اجرا شود؟
مثلاً:
Order Created
↓
Observer / Event
↓
Queue Job
↓
Send Email
در این معماری، Observer یا Event رخداد را اعلام میکند و Job عملیات سنگین را به صف منتقل میکند.
در یک درخواست عادی PHP، Observerهای معمولی بهصورت همزمان و در همان فرآیند اجرا میشوند؛ بنابراین عملیات سنگین داخل Observer میتواند پاسخ را کند کند. برای کارهای زمانبر بهتر است Observer یا Listener صرفاً کار را به Queue بسپارد.
# تست Observer با PHPUnit
یکی از مزیتهای این الگو، امکان تست مستقل Observerهاست.
برای مثال:
<?php
use PHPUnit\Framework\TestCase;
final class EmailObserverTest extends TestCase
{
public function test_observer_is_called(): void
{
$observer = new EmailObserver();
$order = new Order();
$order->attach($observer);
$order->create();
self::assertTrue(true);
}
}
در پروژه واقعی بهتر است بهجای تستی که فقط true را بررسی میکند، رفتار واقعی Observer را با Mock، Fake یا Assertion مناسب بررسی کنیم.
# چه زمانی از Observer Pattern استفاده کنیم؟
Observer انتخاب خوبی است وقتی:
- یک رخداد چند واکنش مستقل دارد.
- تعداد واکنشها ممکن است در آینده افزایش پیدا کند.
- نمیخواهید Subject به جزئیات واکنشها وابسته باشد.
- نیاز به Publish/Subscribe دارید.
- میخواهید مسئولیتها از یکدیگر جدا شوند.
- یک تغییر باید چند بخش مختلف سیستم را مطلع کند.
مثلاً:
PaymentCompleted
↓
┌────┼────┬────┐
↓ ↓ ↓ ↓
Email SMS Log Invoice
این سناریو نمونه بسیار خوبی برای Observer است.
# چه زمانی از Observer استفاده نکنیم؟
اگر فقط یک عملیات ساده بعد از یک اتفاق دارید، استفاده از Observer ممکن است غیرضروری باشد.
مثلاً:
<?php
$user->activate();
و فقط یک خط ساده بعد از آن وجود دارد، احتمالاً نیازی نیست برای آن چند Interface و Observer ایجاد کنیم.
همچنین اگر ترتیب دقیق اجرای چند مرحله اهمیت حیاتی دارد، Observer ممکن است انتخاب مناسبی نباشد؛ چون Observer بیشتر برای واکنشهای مستقل طراحی شده است.
# تفاوت Observer با Strategy
در مقاله قبلی با Strategy Pattern آشنا شدیم.
این دو الگو ممکن است در نگاه اول مشابه به نظر برسند، اما هدفشان متفاوت است.
Strategy
Strategy برای انتخاب بین چند الگوریتم یا رفتار مختلف است.
مثلاً:
Payment
├── Zarinpal
├── IDPay
└── Stripe
Observer
Observer برای اطلاع دادن یک رخداد به چند بخش مختلف است.
مثلاً:
Order Created
├── Email
├── SMS
├── Inventory
└── Log
پس:
> Strategy = انتخاب یک رفتار
> Observer = اطلاعرسانی به چند رفتار
# تفاوت Observer با Command
Command معمولاً یک درخواست یا عملیات را بهصورت یک شیء مستقل کپسوله میکند.
Observer اما بیشتر روی اطلاعرسانی یک رخداد و واکنش چند Observer تمرکز دارد.
برای مثال:
Command
↓
"CreateOrder"
در مقابل:
OrderCreated Event
↓
┌─────┼─────┐
↓ ↓ ↓
Email SMS Log
این دو الگو حتی میتوانند در یک معماری کنار یکدیگر استفاده شوند.
# تفاوت Observer با Mediator
در Observer معمولاً یک Subject به چند Observer اطلاع میدهد.
اما Mediator برای مدیریت ارتباط بین چند شیء مختلف از طریق یک واسط مرکزی استفاده میشود.
بهصورت ساده:
Observer:
Subject
├── Observer
├── Observer
└── Observer
در حالی که:
Mediator:
Object A ──┐
Object B ──┼── Mediator
Object C ──┘
بنابراین Observer بیشتر روی Broadcast یک رخداد تمرکز دارد.
# یک مثال واقعیتر: سیستم فروشگاه اینترنتی
فرض کنید کاربر سفارش خود را پرداخت کرده است.
ما یک Event داریم:
<?php
final class OrderPaid
{
public function __construct(
public readonly int $orderId
) {
}
}
بعد از انتشار این Event چند Listener میتوانند فعال شوند:
OrderPaid
│
├── SendInvoiceEmail
│
├── UpdateInventory
│
├── NotifyAdmin
│
├── UpdateCustomerPoints
│
└── SendToAccounting
این ساختار بسیار بهتر از این است که یک کلاس بزرگ داشته باشیم:
<?php
public function pay(): void
{
// Payment
// Email
// SMS
// Inventory
// Accounting
// CRM
// Analytics
// ...
}
با افزایش امکانات فروشگاه، روش دوم بهسرعت پیچیده میشود.
# نکات مهم در طراحی Observerهای حرفهای
برای اینکه Observer Pattern باعث پیچیدگی پروژه نشود، چند نکته مهم را رعایت کنید.
Observerها را مستقل نگه دارید
بهتر است یک Observer به اجرای موفق Observer دیگر وابسته نباشد.
Observerها را بیش از حد بزرگ نکنید
اگر Observer خودش صدها خط کد دارد، احتمالاً باید مسئولیت آن را به سرویسهای کوچکتر تقسیم کنید.
عملیات سنگین را Queue کنید
برای ایمیل، HTTP Request، پردازش فایل و عملیات مشابه، در پروژههای Laravel بهتر است از Queue استفاده شود.
نامگذاری واضح داشته باشید
نامهایی مانند:
SendWelcomeEmail
UpdateInventory
CreateInvoice
NotifyAdmin
بسیار بهتر از نامهایی مانند:
Observer1
Observer2
Handler
Process
هستند.
مراقب وابستگیهای پنهان باشید
اگر فهمیدن اینکه یک رخداد دقیقاً چه کارهایی انجام میدهد بسیار دشوار شده است، تعداد Eventها و Observerها را بازبینی کنید.
# جمعبندی
Observer Pattern در PHP یکی از الگوهای مهم طراحی رفتاری است که برای ایجاد ارتباط یکبهچند بین یک Subject و چند Observer استفاده میشود.
در این الگو، Subject یک رخداد یا تغییر را اعلام میکند و Observerهای ثبتشده به آن واکنش نشان میدهند.
مهمترین مزیت Observer این است که میتوانیم واکنشهای مختلف را از منطق اصلی برنامه جدا کنیم.
برای مثال در یک فروشگاه:
Order Created
│
├── Send Email
├── Send SMS
├── Update Inventory
├── Create Invoice
└── Write Log
هرکدام از این عملیات میتوانند مستقل باشند و اضافه کردن یک واکنش جدید لزوماً نیازی به تغییر منطق اصلی سفارش نداشته باشد.
PHP نیز با SplSubject و SplObserver امکانات پایه لازم برای پیادهسازی این الگو را در اختیار برنامهنویس قرار میدهد.
در Laravel نیز مفاهیم Event، Listener و Model Observer ابزارهای بسیار کاربردی برای پیادهسازی همین ایده در پروژههای واقعی هستند.
اگر پروژه شما دارای رخدادهایی است که چند بخش مختلف باید به آنها واکنش نشان دهند، Observer Pattern میتواند انتخاب مناسبی باشد؛ اما نباید صرفاً به خاطر استفاده از Design Pattern، ساختار ساده پروژه را پیچیده کنیم.
هدف Design Pattern این نیست که کد بیشتری بنویسیم؛ هدف آن این است که کد را در برابر تغییرات آینده قابل نگهداریتر کنیم.
سوالات متداول
Observer Pattern در PHP چیست؟
Observer Pattern یک الگوی طراحی رفتاری است که اجازه میدهد یک Subject هنگام رخ دادن تغییر یا رویداد، چند Observer را مطلع کند.
Subject در Observer Pattern چیست؟
Subject شیء اصلی است که تغییرات یا رخدادهای آن برای Observerها اهمیت دارد و مسئول اطلاعرسانی به Observerهای ثبتشده است.
Observer در PHP چیست؟
Observer شیئی است که به Subject متصل میشود و هنگام رخ دادن یک تغییر یا رویداد، متد مربوط به واکنش آن اجرا میشود.
آیا PHP خودش Observer Pattern را پشتیبانی میکند؟
PHP دارای Interfaceهای داخلی SplSubject و SplObserver است که میتوان از آنها برای پیادهسازی ساختار Observer استفاده کرد.
تفاوت Observer و Strategy چیست؟
Strategy برای انتخاب بین چند الگوریتم یا رفتار استفاده میشود، در حالی که Observer برای اطلاع دادن یک رخداد به چند Observer کاربرد دارد.
Observer Pattern در Laravel کجا استفاده میشود؟
در Laravel میتوان از Event و Listener برای پیادهسازی الگوی Publish/Subscribe و از Model Observer برای واکنش به lifecycle مدلها استفاده کرد.
آیا Observerها باید عملیات سنگین انجام دهند؟
بهتر است عملیات زمانبر مانند ارسال درخواستهای خارجی، پردازش فایل و برخی عملیات ایمیل به Queue منتقل شوند تا اجرای Observer باعث کند شدن درخواست اصلی نشود.
آیا استفاده از Observer همیشه مناسب است؟
خیر. اگر فقط یک واکنش ساده دارید یا ارتباط بین بخشها بسیار ساده است، استفاده از Observer ممکن است پیچیدگی غیرضروری ایجاد کند.





