متد valid() در PHP
متد valid() یکی از اجزای کلیدی رابط Iterator در PHP است. اگر با ساختن کلاسهای قابل تکرار (iterable) یا کار با ساختارهای دادهٔ از پیش ساختهشدهٔ SPL مثل ArrayIterator یا SplDoublyLinkedList سروکار دارید، فهم دقیق نقش و نحوهٔ پیادهسازی valid() اهمیت زیادی دارد.
مفهوم و امضای متد
در رابط Iterator، امضای متد به این صورت است:
public function valid(): boolاین متد باید بگوید که آیا اشارهگر داخلی (cursor) در موقعیت فعلی به یک عنصر معتبر اشاره میکند یا خیر. نتیجهٔ بازگشتی یک مقدار بولی است: true در صورتی که تکرار ادامه یابد، و false در غیر این صورت.
چرا valid() مهم است؟
- ساختارهایی مثل
foreachیا حلقههای دستی (while) برای خاتمهٔ تکرار ازvalid()استفاده میکنند. - متد باید وضعیت فعلی iterator را بدون ایجاد اثرات جانبی منظم گزارش دهد؛ در غیر این صورت نتایج غیرمنتظره خواهید داشت.
- در generatorها (با
yield) و بسیاری از کلاسهای SPL، رفتار صحیحvalid()تضمینکنندهٔ تکرار ایمن است.
نمونهٔ ساده: پیادهسازی Iterator
class MyIterator implements Iterator {
private array $items;
private int $position = 0;
public function __construct(array $items) {
$this->items = array_values($items);
}
public function rewind(): void {
$this->position = 0;
}
public function current() {
return $this->items[$this->position];
}
public function key(): int {
return $this->position;
}
public function next(): void {
$this->position++;
}
public function valid(): bool {
return isset($this->items[$this->position]);
}
}توضیح: در این کلاس، valid() با استفاده از isset بررسی میکند که آیا برای موقعیت فعلی عنصر وجود دارد یا خیر. این روش سریع و معمول است چون بهاندازهٔ نیاز فقط وجود عنصر را چک میکند و مقدار position را تغییر نمیدهد. متدهای دیگر مانند next() و rewind() وظیفهٔ حرکت نشانگر را برعهده دارند.
استفادهٔ دستی از valid()
$it = new MyIterator([10, 20, 30]);
$it->rewind();
while ($it->valid()) {
echo $it->current() . PHP_EOL;
$it->next();
}توضیح: در این مثال از حلقهٔ while بهصورت دستی استفاده شده است. ابتدا با rewind() نشانگر را به ابتدا میبریم، سپس تا زمانی که valid() مقدار true برگرداند، عنصر فعلی را چاپ و با next() به عنصر بعدی میرویم. این الگویی است که دقیقاً با رفتار داخلی foreach مطابقت دارد.
مثال با کلاسهای SPL و متد valid()
$list = new SplDoublyLinkedList();
$list->push('a');
$list->push('b');
$list->push('c');
$list->rewind();
while ($list->valid()) {
echo $list->current(), PHP_EOL;
$list->next();
}توضیح: ساختارهای آمادهٔ SPL مثل SplDoublyLinkedList متد valid() را پیادهسازی کردهاند. همانگونه که میبینید، نحوهٔ استفاده با نمونهٔ دستی تفاوتی ندارد و میتوانید بهصورت دستی یا با foreach تکرار را انجام دهید.
نکات پیشرفته و بهترین روشها
- اجتناب از تغییر وضعیت در valid(): بهتر است
valid()فقط وضعیت را بررسی کند و نشانگر را حرکت ندهد. تغییر نشانگر درvalid()میتواند منطق تکرار را پیچیده کند و باعث اجرای ناخواستهٔ عملیات شود. - اجراپذیری و کارایی: اگر بررسی اعتبار نیاز به محاسبات سنگین دارد، میتوانید از کش (cache) استفاده کنید یا آن را در متد
next()محاسبه و ذخیره کنید تا هر بار محاسبهٔ مجدد صورت نگیرد. - پذیرش انواع دادهها: هنگام استفاده از
issetیاarray_key_existsدقت کنید که مقادیر null ممکن است باعث خطا در تشخیص شوند؛ انتخاب روش مناسب بسته به دادههای شماست. - سازگاری با Generator: generatorها نیز متد
valid()دارند؛ اما بهصورت پیشفرض PHP مکانیزم تکرار را مدیریت میکند. هیچگاه نباید بهصورت دستی روی داخلی generator تغییر انجام دهید.
پیادهسازی پیشرفته: نادیدهگرفتن مقادیر نامعتبر
class FilteredIterator implements Iterator {
private array $items;
private int $position = 0;
public function __construct(array $items) {
$this->items = array_values($items);
$this->rewind();
}
public function rewind(): void {
$this->position = 0;
$this->skipInvalid();
}
public function current() {
return $this->items[$this->position];
}
public function key(): int {
return $this->position;
}
public function next(): void {
$this->position++;
$this->skipInvalid();
}
public function valid(): bool {
return isset($this->items[$this->position]);
}
private function skipInvalid(): void {
while (isset($this->items[$this->position]) && $this->items[$this->position] === null) {
$this->position++;
}
}
}توضیح: در این پیادهسازی، منطق رد کردن مقادیر نامعتبر داخل یک متد کمکی skipInvalid() قرار گرفته و از next() و rewind() فراخوانی میشود. این الگو تضمین میکند که valid() فقط گزارشدهنده باشد و مسئول تغییر وضعیت نباشد — که یک روش پیشنهادی است.
مقایسهٔ اجمالی متدهای Iterator
| متد | وظیفه |
|---|---|
| rewind() | بازنشانی نشانگر به ابتدا |
| current() | برگرداندن عنصر فعلی |
| key() | برگرداندن کلید عنصر فعلی |
| next() | حرکت به عنصر بعدی |
| valid() | گزارش اعتبار موقعیت فعلی برای ادامهٔ تکرار |
جمعبندی
متد valid() نقش کلیدی در کنترل چرخهٔ تکرار دارد و پیادهسازی صحیح آن برای ساخت کلاسهای iterator قابلاعتماد ضروری است. بهترین روش این است که valid() فقط وضعیت را بررسی کند، منطق حرکت یا فیلتر کردن را در next()/rewind() یا متدهای کمکی قرار دهید، و از آثار جانبی در valid() پرهیز کنید. با رعایت این اصول، هم سازگاری با foreach و ابزارهای SPL حفظ میشود و هم رفتار پیشبینیپذیری خواهید داشت.
آیا این مطلب برای شما مفید بود ؟



