سؤال

$arrayIter = new ArrayIterator( array(1, 2) );
$iterIter = new IteratorIterator($arrayIter);

var_dump($iterIter->valid()); //false
var_dump($arrayIter->valid()); //true

إذا اتصلت أولاً $iterIter->rewind(), ، ثم $iterIter->صالح() صحيح.أشعر بالفضول لماذا يتطلب استدعاء الترجيع ().أتخيل أن هناك سببًا وجيهًا لذلك، لكنني كنت أتوقع أن يبدأ التكرار ببساطة في أي حالة يكون فيها المكرر الداخلي، ويتركه كخيار للترجيع قبل بدء التكرار.

يبدو أيضًا أن استدعاء next() يضعه في حالة "صالحة" (على الرغم من أنه يتقدم إلى الموضع التالي، مما يشير إلى أنه كان في الموضع الأول سابقًا).

$arrayIter = new ArrayIterator(array(1,2));
$iterIter = new IteratorIterator($arrayIter);

$iterIter->next();
var_dump($iterIter->valid()); 

مرة أخرى، أشعر بالفضول بشأن سبب حاجتي إلى استدعاء rewind()، على الرغم من كون المُكرِّر الداخلي في حالة صالحة.

هل كانت مفيدة؟

المحلول

باستخدام مكرر جديد، لا تتم تهيئة الموضع، وذلك لسبب الأداء ببساطة، يمكنك تكديس التكرارات فوق التكرارات الأخرى، إذا تم إرجاعها جميعًا أثناء الإنشاء فسيكون هناك بعض التأثير على الأداء، بالإضافة إلى أن بعض التكرارات قد تغير قيمتها الأولى بعد ذلك تم تنفيذ المُنشئ - وهو أمر غير معروف للمكررين.

عادةً ما يتم تنفيذ التكرارات بواسطة foreach() الذي يقوم بالترجيع() أولاً ...

نصائح أخرى

أثناء تمديد IteratorIterator فئة لتجنيب تنفيذ واجهة التكرار بالكامل و/أو لإنشاء ديكور للمكرر الذي كنت أواجهه في هذا أيضًا.

يعد مصمم الديكور هذا هو الحل للمشكلة بالفعل، فهو يحتاج فقط إلى تنفيذ الوظيفة المفقودة لإزالة عدم الاتساق.لا حاجة للترجيع التلقائي:

class IteratorDecorator extends IteratorIterator
{
    public function valid()
    {
        return $this->getInnerIterator()->valid();
    }
}

مثال:إذا كان لديك Iterator كائن صالح افتراضيًا، على سبيل المثال. ArrayIterator:

$it = new ArrayIterator(array(1));
var_dump($it->valid());             # bool(true)

$itit = new IteratorIterator($it);
var_dump($itit->valid());           # bool(false)

وهذا يدل على عدم التناقض في IteratorIterator التنفيذ بشكل جيد، IteratorIterator الكائن لا يعكس الداخل بشكل صحيح ArrayIteratorحالة.باستخدام IteratorDecorator يمكن أن يشفي هذا:

$decor = new IteratorDecorator($it);
var_dump($decor->valid());          # bool(true)

وإذا كنت قد تابعت الأمر حتى هنا، فإليك حالة خاصة أخرى قد ترغب في وضعها في الاعتبار:إذا لم تكن بحاجة إلى أن يكون لديك rewind مع المكرر الداخلي، يمكنك فقط استخدام NoRewindIterator الذي يُرجع الصلاحية الصحيحة أيضًا:

$noretit = new NoRewindIterator($it);
var_dump($noretit->valid());        # bool(true)

مع أخذ حجج يوهانس "عدم الترجيع التلقائي" في الاعتبار، فإن هذا يبدو منطقيًا، حيث أن NoRewindIterator يتوقع أنه لا ينبغي إرجاع المكرر ويظهر صلاحية المكرر الداخلي بشكل صحيح.

ولكن كما IteratorDecorator في العروض، لا أقوم بأي نوع من الترجيع التلقائي أيضًا لإزالة عدم الاتساق.

كما قال @johannes، لم تتم تهيئة المنصب في IteratorIterator وبالتالي فهو غير صالح قبل تشغيل أي من أساليبه الأخرى أو استخدامه مع foreach()

حاول ان تفعلها

var_dump( $iterIter->current() ); // NULL
var_dump( $iterIter->getInnerIterator()->current() ); // 1

و أيضا

$iterIter->rewind();
var_dump( $iterIter->current() ); // 1
var_dump( $iterIter->getInnerIterator()->->current() );  // 1

ولاحظ أيضًا أنه في IteratorIterator الموحد:

$iterIter->next(); // 2
var_dump( $iterIter->current()) ; // 2 (from NULL to 2)
var_dump( $iterIter->getInnerIterator()->current() );  // 2

لاحظ أن $arrayIter من مقتطف الشفرة الخاص بك مطابق لـ $iterIter->getInnerIterator().

نأمل أن يلقي بعض الضوء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top