در پروژههای PHP و Laravel گاهی لازم است قبل از اجرای یک عملیات، بررسی یا پردازش خاصی انجام شود. برای مثال:
- بررسی کنیم کاربر اجازه دسترسی به یک سرویس را دارد یا خیر.
- نتیجه یک درخواست را در Cache ذخیره کنیم.
- ایجاد یک Object سنگین را تا زمان نیاز به تأخیر بیندازیم.
- زمان اجرای یک سرویس را ثبت کنیم.
- قبل از ارسال درخواست به API، اعتبارسنجی انجام دهیم.
- دسترسی به یک سرویس خارجی یا حساس را محدود کنیم.
اگر این منطق را مستقیماً داخل کلاس اصلی قرار دهیم، ممکن است کلاس ما بیش از حد بزرگ و وابسته شود. همچنین اگر منطق کنترل دسترسی یا Cache را در تمام Clientها تکرار کنیم، نگهداری کد دشوار خواهد شد.
اینجا Proxy Pattern میتواند راهحل مناسبی باشد.
الگوی Proxy یکی از الگوهای ساختاری یا Structural Design Patterns است که یک Object واسط را بین Client و Object اصلی قرار میدهد. این واسط معمولاً همان Interface شیء اصلی را پیادهسازی میکند و درخواستها را پس از انجام پردازشهای لازم به Object واقعی منتقل میکند. <Cite refs={["turn0search0","turn0search1"]} />
Proxy Pattern چیست؟
در الگوی Proxy، به جای اینکه Client مستقیماً با Object اصلی ارتباط داشته باشد، با یک Object جایگزین یا واسط کار میکند.
این Proxy میتواند قبل یا بعد از اجرای متد اصلی، عملیات دیگری انجام دهد؛ برای مثال:
- بررسی مجوز دسترسی
- ثبت Log
- ذخیره نتیجه در Cache
- ایجاد تنبل یا Lazy Object
- محدودکردن تعداد درخواستها
- ارسال درخواست به یک سرویس Remote
- اعتبارسنجی ورودیها
نکته مهم این است که Proxy معمولاً همان Interface مربوط به Object اصلی را پیادهسازی میکند. بنابراین Client لازم نیست بداند که در حال کار با Object واقعی است یا Proxy. <Cite refs={["turn0search0","turn0search1"]} />
به زبان ساده:
Client → Proxy → Real Subject
Client فقط متد موردنظر را صدا میزند. Proxy تصمیم میگیرد که آیا درخواست باید اجرا شود، از Cache پاسخ داده شود یا به Object اصلی منتقل شود.
اجزای اصلی Proxy Pattern
الگوی Proxy معمولاً از چهار بخش تشکیل میشود.
۱. Subject
Subject یک Interface است که متدهای مشترک بین Proxy و Object اصلی را تعریف میکند.
۲. Real Subject
Real Subject همان کلاس اصلی است که منطق واقعی برنامه را اجرا میکند.
۳. Proxy
Proxy همان واسطی است که Interface مشترک را پیادهسازی میکند و به Real Subject دسترسی دارد.
۴. Client
Client بخشی از برنامه است که از Subject استفاده میکند. Client نباید به نوع واقعی Object وابسته باشد.
ساختار کلی:
┌──────────────┐
│ Client │
└──────┬───────┘
│
▼
┌──────────────┐
│ Proxy │
└──────┬───────┘
│
▼
┌──────────────┐
│ Real Subject │
└──────────────┘
مثال ساده Proxy Pattern در PHP
فرض کنید یک سیستم نمایش تصویر داریم. بارگذاری تصویر ممکن است عملیاتی پرهزینه باشد؛ بنابراین نمیخواهیم تصویر از همان لحظه ساخت Object بارگذاری شود.
ابتدا یک Interface تعریف میکنیم:
<?php
declare(strict_types=1);
interface ImageInterface
{
public function display(): void;
}
این Interface متد display را مشخص میکند.
ساخت Real Subject
کلاس RealImage مسئول بارگذاری واقعی تصویر است:
<?php
declare(strict_types=1);
final class RealImage implements ImageInterface
{
public function __construct(
private readonly string $filename
) {
$this->loadFromDisk();
}
private function loadFromDisk(): void
{
echo "Loading image: {$this->filename}" . PHP_EOL;
}
public function display(): void
{
echo "Displaying image: {$this->filename}" . PHP_EOL;
}
}
در Constructor، تصویر از دیسک بارگذاری میشود. در یک پروژه واقعی، این عملیات میتواند شامل خواندن فایل، پردازش تصویر یا دریافت اطلاعات از Storage باشد.
ساخت Proxy
حالا یک Proxy میسازیم که از بارگذاری تصویر تا زمان نیاز جلوگیری میکند:
<?php
declare(strict_types=1);
final class ImageProxy implements ImageInterface
{
private ?RealImage $realImage = null;
public function __construct(
private readonly string $filename
) {
}
public function display(): void
{
if ($this->realImage === null) {
$this->realImage = new RealImage($this->filename);
}
$this->realImage->display();
}
}
در اینجا تصویر هنگام ساخت ImageProxy بارگذاری نمیشود. فقط زمانی که متد display اجرا شود، Object واقعی ساخته خواهد شد.
استفاده از Proxy
<?php
$image = new ImageProxy('products/laptop.jpg');
echo "Proxy created." . PHP_EOL;
$image->display();
echo "Displaying again." . PHP_EOL;
$image->display();
خروجی نمونه:
Proxy created.
Loading image: products/laptop.jpg
Displaying image: products/laptop.jpg
Displaying again.
Displaying image: products/laptop.jpg
همانطور که مشاهده میکنید، پیام Loading image فقط یک بار نمایش داده میشود. Proxy Object واقعی را فقط در اولین اجرای display ایجاد میکند.
این نوع Proxy را معمولاً Virtual Proxy مینامند؛ چون ساخت Object پرهزینه را تا زمان نیاز به تأخیر میاندازد. Lazy Initialization و Caching از کاربردهای رایج Proxy هستند. <Cite refs={["turn0search0","turn0search1"]} />
Proxy چگونه از Lazy Loading استفاده میکند؟
Lazy Loading یعنی Object یا دادهای را فقط زمانی ایجاد یا بارگذاری کنیم که واقعاً به آن نیاز داریم.
بدون Proxy ممکن است کد زیر را داشته باشیم:
$image = new RealImage('products/laptop.jpg');
در این حالت، تصویر بلافاصله بارگذاری میشود؛ حتی اگر هیچوقت از آن استفاده نکنیم.
با Proxy:
$image = new ImageProxy('products/laptop.jpg');
در این مرحله فقط Proxy ساخته میشود. تصویر واقعی در زمان اجرای display بارگذاری خواهد شد.
این روش در شرایط زیر مفید است:
- تصاویر زیاد در یک صفحه وجود دارند.
- Object ساخت سنگینی دارد.
- اطلاعات از API خارجی دریافت میشود.
- اتصال به سرویس هزینهبر است.
- احتمال دارد Object ساخته شود ولی هرگز استفاده نشود.
البته Lazy Loading همیشه باعث بهبود عملکرد نمیشود. اگر Object در تمام حالتها استفاده شود، ساخت Proxy ممکن است پیچیدگی اضافه ایجاد کند. بنابراین باید بر اساس هزینه ساخت Object و الگوی استفاده از آن تصمیم گرفت.
Protection Proxy؛ کنترل دسترسی با Proxy
یکی دیگر از کاربردهای مهم Proxy، کنترل دسترسی است.
فرض کنید یک سرویس برای دریافت گزارش مالی داریم و فقط کاربران مدیر باید بتوانند آن را اجرا کنند.
ابتدا Interface را تعریف میکنیم:
<?php
declare(strict_types=1);
interface ReportServiceInterface
{
public function generate(): string;
}
کلاس اصلی گزارش:
<?php
declare(strict_types=1);
final class FinancialReportService implements ReportServiceInterface
{
public function generate(): string
{
return 'Financial report generated.';
}
}
حالا Proxy را میسازیم:
<?php
declare(strict_types=1);
final class ProtectedReportProxy implements ReportServiceInterface
{
public function __construct(
private readonly ReportServiceInterface $reportService,
private readonly bool $isAdmin
) {
}
public function generate(): string
{
if (!$this->isAdmin) {
throw new RuntimeException(
'You are not allowed to access this report.'
);
}
return $this->reportService->generate();
}
}
استفاده:
<?php
$realService = new FinancialReportService();
$proxy = new ProtectedReportProxy(
reportService: $realService,
isAdmin: false
);
echo $proxy->generate();
در این حالت Exception رخ میدهد؛ چون کاربر مدیر نیست.
برای کاربر مدیر:
<?php
$proxy = new ProtectedReportProxy(
reportService: $realService,
isAdmin: true
);
echo $proxy->generate();
خروجی:
Financial report generated.
مزیت این روش آن است که منطق تولید گزارش در کلاس FinancialReportService باقی میماند و منطق کنترل دسترسی در Proxy قرار میگیرد.
Caching Proxy؛ ذخیره نتیجه درخواست
فرض کنید یک سرویس برای دریافت قیمت دلار، وضعیت آبوهوا یا اطلاعات یک API خارجی داریم. ارسال درخواست در هر بار اجرا میتواند زمانبر یا پرهزینه باشد.
در این شرایط میتوان از Caching Proxy استفاده کرد.
ابتدا Interface:
<?php
declare(strict_types=1);
interface ExchangeRateServiceInterface
{
public function getRate(string $currency): float;
}
سرویس واقعی:
<?php
declare(strict_types=1);
final class RemoteExchangeRateService
implements ExchangeRateServiceInterface
{
public function getRate(string $currency): float
{
echo "Calling remote API..." . PHP_EOL;
return match ($currency) {
'USD' => 60000.0,
'EUR' => 65000.0,
default => 0.0,
};
}
}
حالا Proxy کش:
<?php
declare(strict_types=1);
final class CachedExchangeRateProxy
implements ExchangeRateServiceInterface
{
private array $cache = [];
public function __construct(
private readonly ExchangeRateServiceInterface $service
) {
}
public function getRate(string $currency): float
{
if (array_key_exists($currency, $this->cache)) {
echo "Returning value from cache." . PHP_EOL;
return $this->cache[$currency];
}
$rate = $this->service->getRate($currency);
$this->cache[$currency] = $rate;
return $rate;
}
}
استفاده:
<?php
$service = new RemoteExchangeRateService();
$proxy = new CachedExchangeRateProxy($service);
echo $proxy->getRate('USD') . PHP_EOL;
echo $proxy->getRate('USD') . PHP_EOL;
خروجی:
Calling remote API...
60000
Returning value from cache.
60000
در این مثال، درخواست دوم به API ارسال نمیشود و نتیجه قبلی از Cache خوانده میشود.
در پروژه واقعی Laravel میتوان به جای آرایه از موارد زیر استفاده کرد:
Cache::remember- Redis
- Memcached
- Database Cache
- سیستم Cache اختصاصی
نمونه با Laravel:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
final class CachedProductService
{
public function __construct(
private readonly ProductService $productService
) {
}
public function find(int $productId): array
{
return Cache::remember(
"product:{$productId}",
now()->addMinutes(10),
fn (): array => $this->productService->find($productId)
);
}
}
در این نمونه، Proxy نتیجه سرویس اصلی را در Cache قرار میدهد و در درخواستهای بعدی از مقدار ذخیرهشده استفاده میکند.
Logging Proxy؛ ثبت زمان اجرای سرویس
گاهی لازم است بدون تغییر کلاس اصلی، مدت زمان اجرای یک عملیات را ثبت کنیم.
<?php
declare(strict_types=1);
interface UserServiceInterface
{
public function find(int $id): array;
}
سرویس اصلی:
<?php
declare(strict_types=1);
final class UserService implements UserServiceInterface
{
public function find(int $id): array
{
usleep(200000);
return [
'id' => $id,
'name' => 'Saeed',
];
}
}
Proxy ثبت Log:
<?php
declare(strict_types=1);
final class LoggingUserServiceProxy
implements UserServiceInterface
{
public function __construct(
private readonly UserServiceInterface $service
) {
}
public function find(int $id): array
{
$startedAt = microtime(true);
try {
return $this->service->find($id);
} finally {
$duration = microtime(true) - $startedAt;
error_log(
"UserService::find executed in {$duration} seconds."
);
}
}
}
استفاده:
<?php
$service = new UserService();
$proxy = new LoggingUserServiceProxy($service);
$user = $proxy->find(10);
در این حالت، سرویس اصلی هیچ اطلاعی از ثبت زمان اجرا ندارد و Proxy این مسئولیت را بر عهده گرفته است.
استفاده از Proxy در Laravel
در Laravel، Proxy میتواند برای سرویسهای مختلف کاربرد داشته باشد:
- سرویسهای اتصال به API
- سرویسهای پرداخت
- سرویسهای دریافت نرخ ارز
- سرویسهای ارسال پیامک
- سرویسهای مدیریت فایل
- سرویسهای مربوط به n8n
- سرویسهای گزارشگیری
- سرویسهای دارای Cache
- سرویسهای نیازمند Authorization
- سرویسهای دارای Rate Limit
فرض کنید Interface زیر را داریم:
<?php
namespace App\Contracts;
interface SmsServiceInterface
{
public function send(string $mobile, string $message): bool;
}
سرویس واقعی:
<?php
namespace App\Services;
use App\Contracts\SmsServiceInterface;
final class SmsService implements SmsServiceInterface
{
public function send(string $mobile, string $message): bool
{
// ارسال واقعی پیامک به Provider
return true;
}
}
Proxy برای ثبت Log:
<?php
namespace App\Services;
use App\Contracts\SmsServiceInterface;
use Illuminate\Support\Facades\Log;
final class LoggingSmsProxy implements SmsServiceInterface
{
public function __construct(
private readonly SmsServiceInterface $service
) {
}
public function send(string $mobile, string $message): bool
{
Log::info('SMS sending started', [
'mobile' => $mobile,
]);
$result = $this->service->send($mobile, $message);
Log::info('SMS sending finished', [
'mobile' => $mobile,
'success' => $result,
]);
return $result;
}
}
حالا در Service Container میتوانیم Proxy را به عنوان پیادهسازی Interface ثبت کنیم:
<?php
use App\Contracts\SmsServiceInterface;
use App\Services\LoggingSmsProxy;
use App\Services\SmsService;
$this->app->bind(
SmsServiceInterface::class,
function ($app) {
return new LoggingSmsProxy(
$app->make(SmsService::class)
);
}
);
از این به بعد هر جا Interface را Inject کنیم، Proxy دریافت خواهد شد:
<?php
namespace App\Http\Controllers;
use App\Contracts\SmsServiceInterface;
final class SmsController
{
public function __construct(
private readonly SmsServiceInterface $smsService
) {
}
public function send()
{
$this->smsService->send(
'09120000000',
'Test message'
);
return response()->json([
'message' => 'SMS sent.',
]);
}
}
Controller از وجود Proxy مطلع نیست. این همان ویژگی مهم Proxy است: Client با Interface کار میکند، نه با کلاس پیادهسازی خاص.
تفاوت Proxy و Decorator
Proxy و Decorator شباهت زیادی دارند؛ هر دو میتوانند یک Object را درون خود نگهداری کنند و همان Interface را پیادهسازی کنند.
اما هدف آنها معمولاً متفاوت است.
Proxy
Proxy بیشتر برای موارد زیر استفاده میشود:
- کنترل دسترسی
- Lazy Loading
- Remote Access
- Cache
- مدیریت چرخه عمر Object
- محدودکردن دسترسی به سرویس
Decorator
Decorator معمولاً برای افزودن قابلیتهای جدید به یک Object استفاده میشود؛ مانند:
- افزودن قابلیت فشردهسازی
- افزودن قابلیت رمزنگاری
- افزودن قابلیت ارسال Notification
- افزودن قابلیت گزارشگیری
- ترکیب چند رفتار مختلف
در عمل، تفاوت Proxy و Decorator همیشه کاملاً قطعی نیست. مرز اصلی به هدف طراحی بستگی دارد. اگر تمرکز روی کنترل دسترسی یا جایگزینی Object اصلی باشد، Proxy انتخاب طبیعیتری است. اگر هدف افزودن قابلیتهای قابل ترکیب باشد، Decorator مناسبتر خواهد بود.
تفاوت Proxy و Adapter
Adapter برای سازگارکردن دو Interface متفاوت استفاده میشود.
برای مثال، برنامه ما متد زیر را انتظار دارد:
interface PaymentGatewayInterface
{
public function pay(int $amount): bool;
}
اما Provider خارجی متد دیگری دارد:
$provider->createTransaction($amount);
در اینجا Adapter لازم است تا Interface Provider را با Interface مورد انتظار برنامه سازگار کند.
اما Proxy معمولاً همان Interface Object اصلی را حفظ میکند و قبل یا بعد از اجرای آن عملیات دیگری انجام میدهد.
خلاصه:
| الگو | هدف اصلی |
|---|---|
| Proxy | کنترل یا مدیریت دسترسی به Object |
| Decorator | افزودن رفتار جدید |
| Adapter | سازگارکردن Interfaceهای متفاوت |
| Facade | ارائه یک Interface ساده برای چند سیستم |
انواع Proxy Pattern
Virtual Proxy
برای Lazy Loading و ایجاد Objectهای سنگین در زمان نیاز استفاده میشود.
Protection Proxy
برای کنترل دسترسی کاربران یا نقشها کاربرد دارد.
Remote Proxy
برای دسترسی به سرویس یا Objectی که در سیستم دیگری قرار دارد استفاده میشود.
Caching Proxy
نتیجه درخواستها را ذخیره میکند تا درخواستهای تکراری سریعتر پاسخ داده شوند.
Logging Proxy
اطلاعات مربوط به اجرای متدها، خطاها و زمان پردازش را ثبت میکند.
Smart Proxy
علاوه بر واسطبودن، میتواند مسئولیتهایی مانند مدیریت منابع، شمارش استفاده یا بررسی وضعیت Object را نیز بر عهده بگیرد.
مزایای Proxy Pattern
۱. جداسازی مسئولیتها
منطق اصلی سرویس از منطق کنترل دسترسی، Cache یا Log جدا میشود.
۲. عدم نیاز به تغییر Client
اگر Proxy همان Interface سرویس اصلی را پیادهسازی کند، Client معمولاً نیازی به تغییر ندارد.
۳. امکان Lazy Loading
Objectهای پرهزینه فقط هنگام نیاز ساخته میشوند.
۴. کنترل بهتر دسترسی
میتوان قبل از اجرای عملیات، مجوزها را بررسی کرد.
۵. کاهش درخواستهای تکراری
Caching Proxy میتواند درخواستهای تکراری را مدیریت کند.
۶. تستپذیری بهتر
به کمک Interface و Dependency Injection میتوان Proxy و سرویس اصلی را جداگانه تست کرد.
معایب Proxy Pattern
۱. افزایش تعداد کلاسها
برای یک سرویس ساده ممکن است یک Interface، سرویس اصلی و Proxy ایجاد شود.
۲. پیچیدگی بیشتر
اگر Proxyها بدون نیاز واقعی استفاده شوند، معماری پروژه بیش از حد پیچیده میشود.
۳. احتمال پنهانشدن رفتار واقعی
ممکن است Developer نداند که Object دریافتشده Proxy است و عملیات اضافی مانند Cache یا Authorization انجام میشود.
۴. مدیریت دشوار Cache
در Caching Proxy باید به Expiration، Invalidating Cache و دادههای قدیمی توجه شود.
۵. احتمال ایجاد چندلایه Proxy
اگر چند Proxy پشت سر هم قرار گیرند، Debug کردن جریان درخواست دشوارتر خواهد شد.
چه زمانی از Proxy استفاده کنیم؟
Proxy در شرایط زیر انتخاب مناسبی است:
- سرویس اصلی هزینه پردازشی بالایی دارد.
- میخواهیم ساخت Object را به تأخیر بیندازیم.
- نیاز به کنترل دسترسی داریم.
- میخواهیم نتیجه درخواستها Cache شود.
- سرویس خارجی یا Remote داریم.
- نیاز به ثبت Log بدون تغییر کلاس اصلی داریم.
- میخواهیم قابلیت Rate Limiting یا Retry را جدا کنیم.
- کلاس اصلی متعلق به یک پکیج خارجی است و نمیخواهیم آن را تغییر دهیم.
چه زمانی از Proxy استفاده نکنیم؟
اگر سرویس بسیار ساده است و هیچ رفتار اضافی نیاز ندارد، استفاده از Proxy ممکن است فقط پیچیدگی ایجاد کند.
همچنین اگر هدف شما ترکیب چند رفتار مستقل و قابل تعویض است، Decorator یا Middleware ممکن است انتخاب مناسبتری باشد.
تست Proxy با PHPUnit
برای تست Caching Proxy میتوان بررسی کرد که سرویس واقعی فقط یک بار اجرا شده است.
ابتدا یک Fake Service میسازیم:
<?php
declare(strict_types=1);
final class FakeRateService implements ExchangeRateServiceInterface
{
public int $calls = 0;
public function getRate(string $currency): float
{
$this->calls++;
return 60000.0;
}
}
تست:
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class CachedExchangeRateProxyTest extends TestCase
{
public function test_it_caches_repeated_requests(): void
{
$fakeService = new FakeRateService();
$proxy = new CachedExchangeRateProxy($fakeService);
$firstRate = $proxy->getRate('USD');
$secondRate = $proxy->getRate('USD');
self::assertSame(60000.0, $firstRate);
self::assertSame(60000.0, $secondRate);
self::assertSame(1, $fakeService->calls);
}
}
در این تست، متد getRate دو بار روی Proxy اجرا میشود؛ اما سرویس واقعی فقط یک بار فراخوانی میشود.
برای Protection Proxy نیز میتوان تست کرد که کاربر غیرمجاز نمیتواند به سرویس دسترسی داشته باشد:
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ProtectedReportProxyTest extends TestCase
{
public function test_non_admin_cannot_generate_report(): void
{
$service = new FinancialReportService();
$proxy = new ProtectedReportProxy(
reportService: $service,
isAdmin: false
);
$this->expectException(RuntimeException::class);
$proxy->generate();
}
}
اشتباهات رایج هنگام استفاده از Proxy
اشتباه اول: قرار دادن تمام منطق برنامه در Proxy
Proxy نباید به یک کلاس بزرگ و پیچیده تبدیل شود. بهتر است هر Proxy یک مسئولیت مشخص داشته باشد.
اشتباه دوم: نداشتن Interface مشترک
اگر Proxy و Real Subject Interface مشترکی نداشته باشند، Client ممکن است به کلاس خاصی وابسته شود.
اشتباه سوم: Cache بدون Expiration
ذخیره دائمی دادهها میتواند باعث نمایش اطلاعات قدیمی شود. Cache باید زمان انقضا و روش پاکسازی داشته باشد.
اشتباه چهارم: کنترل دسترسی فقط در Proxy
Proxy میتواند یک لایه کنترل دسترسی باشد، اما برای عملیات حساس باید مجوزها در سطح مناسب سیستم نیز بررسی شوند.
اشتباه پنجم: ایجاد Proxy برای همه کلاسها
Proxy یک ابزار طراحی است، نه چیزی که باید در تمام سرویسها استفاده شود. فقط زمانی از آن استفاده کنید که نیاز مشخصی وجود داشته باشد.
اشتباه ششم: پنهانکردن خطاها
Proxy نباید خطاهای سرویس اصلی را بدون دلیل مخفی کند. در صورت نیاز باید خطا ثبت، تبدیل یا دوباره پرتاب شود.
نمونه کامل Proxy Pattern در PHP
کد زیر یک نمونه ساده و کامل از Proxy برای Cache را نشان میدهد:
<?php
declare(strict_types=1);
interface ProductServiceInterface
{
public function find(int $id): array;
}
final class ProductService implements ProductServiceInterface
{
public function find(int $id): array
{
echo "Loading product from database." . PHP_EOL;
return [
'id' => $id,
'title' => 'Laptop',
'price' => 50000000,
];
}
}
final class ProductCacheProxy implements ProductServiceInterface
{
private array $cache = [];
public function __construct(
private readonly ProductServiceInterface $service
) {
}
public function find(int $id): array
{
if (isset($this->cache[$id])) {
echo "Loading product from cache." . PHP_EOL;
return $this->cache[$id];
}
$product = $this->service->find($id);
$this->cache[$id] = $product;
return $product;
}
}
function showProduct(ProductServiceInterface $service): void
{
$product = $service->find(1);
echo $product['title'] . PHP_EOL;
}
$realService = new ProductService();
$proxy = new ProductCacheProxy($realService);
showProduct($proxy);
showProduct($proxy);
خروجی:
Loading product from database.
Laptop
Loading product from cache.
Laptop
تابع showProduct نمیداند که Object دریافتی یک سرویس واقعی است یا Proxy. این موضوع باعث میشود بتوانیم رفتار سرویس را بدون تغییر کد Client مدیریت کنیم.
جمعبندی
Proxy Pattern در PHP یک الگوی ساختاری است که یک Object واسط را بین Client و Object اصلی قرار میدهد.
Proxy میتواند قبل یا بعد از اجرای عملیات اصلی، کارهایی مانند موارد زیر را انجام دهد:
- کنترل دسترسی
- Cache
- Lazy Loading
- ثبت Log
- مدیریت درخواستهای Remote
- کنترل منابع
- اعتبارسنجی
- Rate Limiting
مهمترین ویژگی Proxy این است که معمولاً همان Interface مربوط به Real Subject را پیادهسازی میکند. بنابراین Client میتواند بدون اطلاع از جزئیات، با Proxy کار کند.
در پروژههای PHP و Laravel، این الگو برای سرویسهای API، پرداخت، پیامک، گزارشگیری، Storage، مدیریت محصولات و سرویسهای پرهزینه کاربرد زیادی دارد. با این حال، استفاده از Proxy باید بر اساس نیاز واقعی انجام شود؛ زیرا در پروژههای کوچک ممکن است پیچیدگی غیرضروری ایجاد کند.
سوالات متداول
Proxy Pattern در PHP چیست؟
Proxy Pattern یک الگوی ساختاری است که یک Object جایگزین را بین Client و Object اصلی قرار میدهد تا بتواند کنترل دسترسی، Cache، Lazy Loading یا عملیات دیگری را مدیریت کند.
تفاوت Proxy و Decorator چیست؟
Proxy بیشتر برای کنترل دسترسی، مدیریت چرخه عمر یا جایگزینی Object اصلی استفاده میشود؛ در حالی که Decorator معمولاً برای افزودن رفتارهای جدید و قابل ترکیب به یک Object کاربرد دارد.
آیا Proxy همیشه باعث افزایش سرعت میشود؟
خیر. Proxy در شرایطی مانند Cache یا Lazy Loading میتواند عملکرد را بهتر کند، اما خود Proxy نیز پیچیدگی و یک لایه اضافی به سیستم اضافه میکند.
آیا Proxy در Laravel کاربرد دارد؟
بله. میتوان Proxy را برای سرویسهای API، Cache، پیامک، پرداخت، گزارشگیری، کنترل دسترسی و سرویسهای خارجی در Laravel استفاده کرد.
Virtual Proxy چیست؟
Virtual Proxy نوعی Proxy است که ساخت Object سنگین را تا زمانی که واقعاً به آن نیاز باشد به تأخیر میاندازد.
Protection Proxy چه کاربردی دارد؟
Protection Proxy برای بررسی مجوز دسترسی قبل از اجرای عملیات اصلی استفاده میشود؛ برای مثال محدودکردن دسترسی به گزارش مالی یا اطلاعات محرمانه.
آیا Proxy باید همان Interface سرویس اصلی را داشته باشد؟
در طراحی معمول Proxy، بله. داشتن Interface مشترک باعث میشود Client بتواند بدون تغییر با Proxy یا Real Subject کار کند. <Cite refs={["turn0search0","turn0search1"]} />





