ژنراتور در PHP چیست؟  با Generators در PHP آشنا بشیم

ژنراتور در PHP چیست؟ با Generators در PHP آشنا بشیم

بصورت کلی ژنراتور اجازه میدن تا روی مجموعه‌ای از داده‌ها بدون بارگذاری کل مجموعه در حافظه، پیمایش کنیم.این ویژگی زمانیکه با مجموعه‌های داده بزرگ یا داده‌های جریانی(Date Stream) کار میکنیم خیلی مفید هست.

همونطور که می دونیم توی دنیای توسعه وب، بهینه‌سازی عملکرد و مدیریت منابع اهمیت بسیار زیادی داره. یکی از ویژگی‌های قدرتمند اما کمتر شناخته شده در PHP، ژنراتورها هستند.

ژنراتورها(Generators) روشی بهینه برای پیمایش داده‌ها بدون نیاز به بارگذاری تمام داده‌ها در حافظه رو فراهم می‌کنن. این قابلیت به ویژه هنگام کار با مجموعه‌های داده بزرگ یا جریان‌های داده پیوسته مفید هست.

توی این مقاله، به بررسی مزایا و کاربردهای ژنراتورهای PHP و نحوه استفاده از آن‌ها در پروژه‌های توسعه وب می‌پردازیم.

با ما همراه باشید تا ببینید چگونه میشه با استفاده از ژنراتورها، کارایی و کارآمدی کدهای PHP رو بهبود بخشید:

 

ژنراتورهای PHP چه هستند؟

بصورت کلی ژنراتور اجازه میدن تا روی مجموعه‌ای از داده‌ها بدون بارگذاری کل مجموعه در حافظه، پیمایش کنیم.

این ویژگی زمانی مفید هست که با مجموعه‌های داده بزرگ یا داده‌های جریانی کار میکنیم.

ژنراتورها از کلیدواژه yield برای بازیابی مقادیر یکی یکی استفاده می‌کنند، که اجرای کد را متوقف کرده و حالت را بین هر مقدار ذخیره می‌کند.

خوب فرض کنید کد زیر موجود هست و ما آرایه ای صد عضوی بصورت زیر داریم:

$numbers = range(1, 100);

foreach ($numbers as $number) {
    echo $number;
}

کد بالا یک آرایه از ۱۰۰ عدد ایجاد و سپس بر روی آن پیمایش می‌کند. این روش روی آرایه های کوچک به خوبی جوابگو هست. اما برای آرایه های بزرگ بخاطر مصرف زیاد منابع مشکلاتی ایجاد خواهد شد.

حالا کد بالا رو با استفاده از ژنراتورها باز نویسی می کنیم:
 

function generateNumbers($max) {
    for ($i = 1; $i <= $max; $i++) {
        yield $i;
    }
}

foreach (generateNumbers(100) as $number) {
    echo $number;
}

توی این حالت، generateNumbers اعداد رو یکی یکی تولید می‌کنه بدون اینکه یک آرایه بزرگ ایجاد کنه که این کار مصرف حافظه را کاهش می‌دهد.

 

اما استفاده از ژنراتورها چطور مصرف حافظه رو کاهش میده؟

ژنراتورها مصرف حافظه را به این دلیل کاهش می‌دهند که مقادیر را یکی یکی تولید می‌کنن و نیازی به ایجاد و نگهداری آرایه‌های بزرگ توی حافظه ندارند.

در روش‌های اول، تمام داده‌ها به یکباره در حافظه بارگذاری میشن، اما ژنراتورها فقط یک مقدار را در هر لحظه نگه می‌دارند و پس از پردازش آن، به مقدار بعدی می‌روند.

این روش به خصوص هنگام کار با مجموعه‌ داده های بزرگ و جریان‌های داده مفید هست، چونکه حافظه مورد نیاز را به حداقل می‌رساند و از مصرف بی‌رویه منابع جلوگیری می‌کند.

 

نحوه کار ژنراتورها

ژنراتورها با استفاده از توابعی که شامل یک یا چند عبارت yield هستند، ایجاد میشن. وقتی یک تابع ژنراتور فراخوانی میشه، یک شیء که رابط Iterator را پیاده‌سازی می‌کند برمی‌گرداند. ژنراتور کد خود را تا زمانی که پیمایش آغاز نشود، اجرا نمی‌کند.

 نکته: PHP، Iterator یک رابط (interface) است که الگوی طراحی تکرار (Iterator Pattern) را پیاده‌سازی می‌کنه. این الگو به شما اجازه می‌ده تا بر روی مجموعه‌ای از عناصر به صورت دنباله‌ای (sequential) پیمایش کنید بدون اینکه جزئیات داخلی آن مجموعه را بدانید. Iteratorها به ویژه برای کار با مجموعه‌های داده پیچیده و بزرگ مفید هستند.

 

کد زیر رو با دقت ببینید:

function getLinesFromFile($file) {
    $handle = fopen($file, 'r');

    if ($handle) {
        while (($line = fgets($handle)) !== false) {
            yield $line;
        }
        fclose($handle);
    } else {
        throw new Exception("Could not open the file!");
    }
}

foreach (getLinesFromFile('example.txt') as $line) {
    echo $line;
}

توی مثال بالا، getLinesFromFile به جای اینکه بیاد و کل فایل رو بگیره و همزمان در حافظه بارگزاری کنه، فایل رو بصورت خ به خط می خونه و برمیگرونه. این باعث میشه که در پردازش های بزرگ ما کمتر مشکلات مربوط به حافظه رو داشته باشیم.

 

ویژگی‌های کلیدی ژنراتورها

  • کارایی حافظه: ژنراتورها تنها یک مقدار را در هر زمان در حافظه نگه می‌دارند.
  • حفظ حالت: ژنراتورها حالت خود را بین تکرارها حفظ می‌کنند، که این کار پیمایش‌های پیچیده‌تر را آسان‌تر می‌کند.
  • ارزیابی تنبل: ژنراتورها مقادیر را بر حسب نیاز تولید می‌کنند که این کار می‌تواند عملکرد را برای مجموعه‌های داده بزرگ بهبود بخشد.

 

در ادامه چند نمونه از استفاده ژنراتور ها رو با همدیگه بررسی میکنیم:

از ژنراتوها می تونیم در هنگام کار با پایگاه داده های بزرگ استفاده کنیم. این باعث میشه تمام رکورد ها بصورت همزمان به حافظه منتقل نشن و در مصرف حافظه صرفه جویی خواهد شد. نمونه کد زیر اطلاعات دریافتی از دیتابیس رو با استفاده از ژنراتور پردازش میکنه:

function fetchRecords($pdo, $query) {
    $stmt = $pdo->prepare($query);
    $stmt->execute();
    
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        yield $row;
    }
}

$pdo = new PDO();
$query = "SELECT * FROM large_table";

foreach (fetchRecords($pdo, $query) as $record) {
    var_dump($record);
}

 

کار با Data Stream:

ژنراتورها به دلیل توانایی تولید مقادیر به صورت تدریجی و در لحظه، برای کار با جریان‌های داده (Data Stream) بسیار مناسب هستند. به جای بارگذاری همه داده‌ها در حافظه، ژنراتورها فقط یک مقدار را در هر لحظه تولید می‌کنند و پس از پردازش آن، به مقدار بعدی می‌رن.

 این ویژگی به خصوص زمانیکه داده‌ها به صورت پیوسته و در حجم بالا منتقل میشن، مفید هست.

 

یه نمونه از استفاده از ژنراتورها برای ایجاد Data Stream در زیر اومده که با همدیگه اون رو میبینیم:

function apiDataStream() {
    $data = [
        ['id' => 1, 'name' => 'John'],
        ['id' => 2, 'name' => 'Jane'],
        ['id' => 3, 'name' => 'Doe']
    ];
    
    foreach ($data as $item) {
        yield $item;
        sleep(1);
    }
}

foreach (apiDataStream() as $data) {
    echo $data['name'] . "\n";
}

 

مدیریت مقادیر برگشتی ژنراتور

از PHP 7 به بعد، ژنراتورها می‌توانند با استفاده از کلمه کلیدی return مقدار برگردانند. این مقدار رو میشه با استفاده از روش getReturn در شیء ژنراتور بازیابی کرد:

function countToFive() {
    for ($i = 1; $i <= 5; $i++) {
        yield $i;
    }
    return "I am done";
}

$generator = countToFive();

foreach ($generator as $number) {
    echo $number . "\n";
}

echo $generator->getReturn(); // Outputs: I am done

 

علاوه بر این ژنراتورها می‌توانند به یک ژنراتور دیگر با استفاده از دستور yield from تفویض(Delegation) کنند.

نکته: Delegation در برنامه‌نویسی به معنای واگذاری وظایف یا مسئولیت‌های خاص از یک شیء به شیء دیگر هست. این مفهوم به ویژه در زمینه طراحی الگوهای شیء‌گرا (Object-Oriented Design) اهمیت دارد، جایی که یک شیء میتونه عملیات یا وظایف خاصی را به شیء دیگر واگذار کند تا از تکرار کد و افزایش انعطاف‌پذیری جلوگیری شود.

این کار فرآیند عبور مقادیر از ژنراتورهای تودرتو را ساده می‌کند:

function innerGenerator() {
    yield 1;
    yield 2;
}

function outerGenerator() {
    yield from innerGenerator();
    yield 3;
}

foreach (outerGenerator() as $value) {
    echo $value . "\n"; // Outputs: 1, 2, 3
}

 

نتیجه گیری:

ژنراتورهای PHP ابزارهای قدرتمندی برای پردازش و پیمایش کارآمد داده‌ها هستند که صرفه‌جویی قابل توجهی در حافظه ایجاد می‌کنند و امکان ارزیابی تنبل رو فراهم می‌کنند. 

این ویژگی‌ها ژنراتورها رو برای پردازش مجموعه‌های داده بزرگ و جریان‌ها بهینه میکنه.

 استفاده از ژنراتورها در برنامه‌های PHP عملکرد رو بهبود میبخشه و مصرف منابع رو کاهش میده و به باعث میشه کدی که نوشته بشه به کدی مقیاس‌پذیر و کارآمدتر تبدیل بشه.

دفعه بعد که نیاز به پردازش مقدار زیادی داده یا کار با جریان‌ها داشتید، ژنراتورهای PHP رو مدنظر قرار دهید. چون ژنراتورها کمک های زیادی توی مصرف حافظه به شما میکنند.

 

امیدوارم این مطلب برای شما مفید باشه اگر شما هم در مورد ژنراتور های اطلاعات مفیدی دارید از بخش نظرات برای ما ارسال کنید. :)

 


برچسب ها:

php آموزش php php Generator

دسته بندی ها:

پی اچ پی

ارسال نظر

برای اطلاع از پاسخ به نظر شما می توانید ایمیل یا شماره موبایل خود را وارد نمایید. *

ایمیل و شماره موبایل شما کاملا مخفی خواهد ماند و در سایت نمایش داده نخواهد شد. *

اگر نظری برای این مطلب ارسال شد از طریق ایمیل مرا اطلاع بده!
لسیت نظرات
هنوز برای این مطلب نظری ارسال نشده است!