php - কিভাবে পিএইচপি 'foreach' আসলে কাজ করে?




loops iteration (5)

উদাহরণস্বরূপ 3 আপনি অ্যারে পরিবর্তন করবেন না। অন্যান্য সমস্ত উদাহরণে আপনি বিষয়বস্তু বা অভ্যন্তরীণ অ্যারে পয়েন্টারটি সংশোধন করেন। অ্যাসাইনমেন্ট অপারেটরের সেমেটিকসের কারণে এটি PHP অ্যারেগুলির ক্ষেত্রে গুরুত্বপূর্ণ।

পিএইচপি এ অ্যারে জন্য অ্যাসাইনমেন্ট অপারেটর একটি অলস ক্লোন মত কাজ করে। একটি পরিবর্তনশীলকে অন্য একটি অ্যারে অন্তর্ভুক্ত করে যা একটি অ্যারে ক্লোন করবে, বেশিরভাগ ভাষার বিপরীতে। যাইহোক, এটি প্রয়োজন না হওয়া পর্যন্ত প্রকৃত ক্লোনিং করা হবে না। এর অর্থ হল ক্লোনটি কেবল তখনই সঞ্চালিত হবে যখন ভেরিয়েবলগুলির মধ্যে কোনটি সংশোধন করা হবে (অনুলিপি অনুলিপি)।

এখানে একটি উদাহরণ:

$a = array(1,2,3);
$b = $a;  // This is lazy cloning of $a. For the time
          // being $a and $b point to the same internal
          // data structure.

$a[] = 3; // Here $a changes, which triggers the actual
          // cloning. From now on, $a and $b are two
          // different data structures. The same would
          // happen if there were a change in $b.

আপনার পরীক্ষা ক্ষেত্রে ফিরে আসছে, আপনি সহজেই কল্পনা করতে পারেন যে foreach অ্যারের একটি রেফারেন্স সহ কিছু ধরনের ইটারারেটর তৈরি করে। এই রেফারেন্স আমার উদাহরণে পরিবর্তনশীল $b ঠিক মত কাজ করে। যাইহোক, রেফারেন্স বরাবর ইথারেটর শুধুমাত্র লুপ সময় বাস এবং তারপর, তারা উভয় বাতিল করা হয়। এখন আপনি দেখতে পারেন যে, সব ক্ষেত্রে 3, অ্যারে লুপের সময় সংশোধন করা হয়, যখন এই অতিরিক্ত রেফারেন্স জীবিত। এটি একটি ক্লোন ট্রিগার করে, এবং এখানে কী চলছে তা ব্যাখ্যা করে!

এখানে অনুলিপি আচরণের অন্য পার্শ্বপ্রতিক্রিয়াটির জন্য একটি চমৎকার নিবন্ধ: পিএইচপি টার্নারি অপারেটর: দ্রুত বা না?

আমি এই foreach যে foreach হয়, কি করে এবং কিভাবে এটি ব্যবহার করে আমি এই উপসর্গ। এই প্রশ্নটি বননেটের অধীনে কীভাবে কাজ করে সে বিষয়ে উদ্বেগ প্রকাশ করে এবং আমি "আপনি কিভাবে foreach সাথে একটি অ্যারে লুপ করেন" এর রেখা বরাবর কোন উত্তর চাই না।

একটি দীর্ঘ সময় আমি অনুমান যে foreach অ্যারে নিজেই সঙ্গে কাজ। তারপরে আমি এই রেটির বেশিরভাগ রেফারেন্স খুঁজে পেয়েছি যে এটি অ্যারের একটি অনুলিপি দিয়ে কাজ করে এবং আমি তখন থেকেই এটি গল্পের শেষ বলে মনে করি। কিন্তু সম্প্রতি আমি বিষয়টি নিয়ে আলোচনা শুরু করেছি, এবং একটু পরীক্ষার পরে এটি আসলে 100% সত্য ছিল না।

আমাকে কি বলতে চাও। নিম্নলিখিত পরীক্ষার ক্ষেত্রে, আমরা নিম্নলিখিত অ্যারের সাথে কাজ করবো:

$array = array(1, 2, 3, 4, 5);

পরীক্ষার ক্ষেত্রে 1 :

foreach ($array as $item) {
  echo "$item\n";
  $array[] = $item;
}
print_r($array);

/* Output in loop:    1 2 3 4 5
   $array after loop: 1 2 3 4 5 1 2 3 4 5 */

এটি স্পষ্টভাবে দেখায় যে আমরা সোর্স অ্যারের সাথে সরাসরি কাজ করছি না - অন্যথায় লুপ চিরতরে চলবে, কারণ আমরা ক্রমাগত লুপের সময় অ্যারেতে আইটেমগুলিকে ধাক্কা দিচ্ছি। কিন্তু শুধু এই ক্ষেত্রে নিশ্চিত করা:

টেস্ট কেস 2 :

foreach ($array as $key => $item) {
  $array[$key + 1] = $item + 2;
  echo "$item\n";
}

print_r($array);

/* Output in loop:    1 2 3 4 5
   $array after loop: 1 3 4 5 6 7 */

এটি আমাদের প্রাথমিক উপসংহারের ব্যাক আপ করে, আমরা লুপের সময় উৎস অ্যারের একটি অনুলিপি দিয়ে কাজ করছি, অন্যথায় আমরা লুপের সময় সংশোধিত মানগুলি দেখব। কিন্তু ...

আমরা manual , আমরা এই বিবৃতি খুঁজে পেতে:

Foreach প্রথম নির্বাহ শুরু করা হয়, অভ্যন্তরীণ অ্যারে পয়েন্টার স্বয়ংক্রিয়ভাবে অ্যারের প্রথম উপাদান থেকে রিসেট করা হয়।

ঠিক আছে ... মনে হচ্ছে যে foreach উৎস অ্যারের অ্যারে পয়েন্টার উপর নির্ভর করে। কিন্তু আমরা প্রমাণ করেছি যে আমরা উৎস অ্যারের সাথে কাজ করছি না , তাই না? আচ্ছা, সম্পূর্ণভাবে না।

টেস্ট কেস 3 :

// Move the array pointer on one to make sure it doesn't affect the loop
var_dump(each($array));

foreach ($array as $item) {
  echo "$item\n";
}

var_dump(each($array));

/* Output
  array(4) {
    [1]=>
    int(1)
    ["value"]=>
    int(1)
    [0]=>
    int(0)
    ["key"]=>
    int(0)
  }
  1
  2
  3
  4
  5
  bool(false)
*/

সুতরাং, আমরা সোর্স অ্যারের সাথে সরাসরি কাজ করছি না সত্ত্বেও, আমরা সোর্স অ্যারে পয়েন্টারের সাথে সরাসরি কাজ করছি - লুপের শেষে পয়েন্টারটি অ্যারের শেষে এটি দেখায়। এটি সত্য নাও হতে পারে - যদি এটি হয়, তবে পরীক্ষার ক্ষেত্রে 1 টি চিরতরে লুপ হবে।

পিএইচপি ম্যানুয়াল এছাড়াও বলেছেন:

Foreach হিসাবে লুপ মধ্যে এটি পরিবর্তন অভ্যন্তরীণ অ্যারে পয়েন্টার উপর নির্ভর করে হিসাবে অপ্রত্যাশিত আচরণ হতে পারে।

আচ্ছা, আসুন "অপ্রত্যাশিত আচরণ" কী তা খুঁজে বের করি (টেকনিক্যালি, কোনও আচরণ অপ্রত্যাশিত, যেহেতু আমি আর কি আশা করি তা জানি না)।

টেস্ট কেস 4 :

foreach ($array as $key => $item) {
  echo "$item\n";
  each($array);
}

/* Output: 1 2 3 4 5 */

টেস্ট কেস 5 :

foreach ($array as $key => $item) {
  echo "$item\n";
  reset($array);
}

/* Output: 1 2 3 4 5 */

... যে অপ্রত্যাশিত কিছু নেই, আসলে এটি "উৎসের কপি" তত্ত্বকে সমর্থন করে।

প্রশ্নটি

এখানে কি হচ্ছে? পিএইচপি সোর্স কোডটি দেখে কেবল আমার সি-ফু যথেষ্ট সঠিক উপসংহারে বেরিয়ে আসতে সক্ষম হয় না, কেউ যদি আমার জন্য এটি ইংরেজীতে অনুবাদ করতে পারে তবে আমি কৃতজ্ঞ।

আমার মনে হয় যে foreach অ্যারের একটি অনুলিপি দিয়ে কাজ করে, কিন্তু লুপের পরে অ্যারের শেষে উৎস অ্যারের অ্যারের পয়েন্টার সেট করে।

  • এই সঠিক এবং পুরো গল্প?
  • যদি না হয়, এটা সত্যিই কি করছেন?
  • অ্যারে পয়েন্টার ( each() , reset() ইত্যাদি সামঞ্জস্য করে এমন ফাংশনগুলি ব্যবহার করে কোনও foreach কি লুপের ফলাফলকে প্রভাবিত করতে পারে?

foreach() সঙ্গে কাজ করার সময় কিছু পয়েন্ট নোট:

একটি) foreach মূল অ্যারের প্রত্যাশিত অনুলিপি কাজ করে। এটি foreach () একটি prospected copy তৈরি করা হয় না manual তৈরি না হওয়া পর্যন্ত তথ্য সঞ্চয় স্টোরেজ হবে।

খ) কি একটি প্রত্যাশিত কপি ট্রিগার? প্রত্যাশিত অনুলিপি অনুলিপি অনুলিপি নীতির উপর ভিত্তি করে তৈরি করা হয়, অর্থাৎ, যখনই কোনও অ্যারে ফোরাম () পরিবর্তন করা হয়, তখন মূল অ্যারের একটি ক্লোন তৈরি করা হয়।

গ) আসল অ্যারে এবং foreach () ইটারারেটরের DISTINCT SENTINEL VARIABLES থাকবে, যা একটি মৌলিক অ্যারের জন্য এবং foreach এর জন্য অন্য; নিচে পরীক্ষা কোড দেখুন। SPL , Iterators , এবং অ্যারে Iterator

স্ট্যাক ওভারফ্লো প্রশ্ন কিভাবে পিএইচপি একটি 'foreach' লুপ মান পুনরায় সেট করা হয় তা নিশ্চিত করতে? আপনার প্রশ্নের ক্ষেত্রে (3,4,5) ঠিকানা।

নিম্নলিখিত উদাহরণটি দেখায় যে প্রতিটি () এবং রিসেট () foreach () SENTINEL ভেরিয়েবলগুলি (for example, the current index variable) প্রভাবিত করে না।

$array = array(1, 2, 3, 4, 5);

list($key2, $val2) = each($array);
echo "each() Original (outside): $key2 => $val2<br/>";

foreach($array as $key => $val){
    echo "foreach: $key => $val<br/>";

    list($key2,$val2) = each($array);
    echo "each() Original(inside): $key2 => $val2<br/>";

    echo "--------Iteration--------<br/>";
    if ($key == 3){
        echo "Resetting original array pointer<br/>";
        reset($array);
    }
}

list($key2, $val2) = each($array);
echo "each() Original (outside): $key2 => $val2<br/>";

আউটপুট:

each() Original (outside): 0 => 1
foreach: 0 => 1
each() Original(inside): 1 => 2
--------Iteration--------
foreach: 1 => 2
each() Original(inside): 2 => 3
--------Iteration--------
foreach: 2 => 3
each() Original(inside): 3 => 4
--------Iteration--------
foreach: 3 => 4
each() Original(inside): 4 => 5
--------Iteration--------
Resetting original array pointer
foreach: 4 => 5
each() Original(inside): 0=>1
--------Iteration--------
each() Original (outside): 1 => 2

পিএইচপি 7 জন্য উল্লেখ্য

এই উত্তরটি আপডেট করার জন্য এটি কিছু জনপ্রিয়তা অর্জন করেছে: এই উত্তরটি আর পিএইচপি 7 হিসাবে প্রযোজ্য নয়। পিএইচপি 7 ফোরামে " ব্যাকগ্রাউন্ড অসঙ্গতিপূর্ণ পরিবর্তন " হিসাবে ব্যাখ্যা করা হয়েছে, অ্যারের অনুলিপিটি কাজ করে, তাই অ্যারের কোনও পরিবর্তন foreach লুপ প্রতিফলিত হয় না। লিঙ্ক এ আরো বিস্তারিত।

ব্যাখ্যা ( php.net থেকে উদ্ধৃতি):

Array_expression দ্বারা প্রদত্ত অ্যারের উপর প্রথম ফর্মটি loops। প্রতিটি পুনরাবৃত্তির উপর, বর্তমান উপাদানটির মান $ মান নির্ধারণ করা হয় এবং অভ্যন্তরীণ অ্যারে পয়েন্টারটি এক দ্বারা উন্নত হয় (তাই পরবর্তী পুনরাবৃত্তির পরে, আপনি পরবর্তী উপাদানটি দেখবেন)।

সুতরাং, আপনার প্রথম উদাহরণে আপনার অ্যারেতে কেবল একটি উপাদান রয়েছে এবং যখন পয়েন্টার সরানো হয় তখন পরবর্তী উপাদানটি বিদ্যমান থাকে না, তাই আপনি নতুন উপাদান যোগ করার পরে foreach শেষ হয় কারণ এটি ইতিমধ্যে "সিদ্ধান্ত নিয়েছে" যে এটি শেষ উপাদান হিসাবে।

আপনার দ্বিতীয় উদাহরণে, আপনি দুটি উপাদানের সাথে শুরু করুন এবং ফোরাম লুপ শেষ উপাদানটিতে নয় তাই এটি পরবর্তী পুনরাবৃত্তির অ্যারের মূল্যায়ন করে এবং এভাবে অ্যারেতে নতুন উপাদান রয়েছে তা উপলব্ধি করে।

আমি বিশ্বাস করি যে এটি সমস্ত ফলাফলের ডকুমেন্টেশনের ব্যাখ্যাটির প্রতিটি পুনরাবৃত্তি অংশে, যা সম্ভবত foreachকোডটি কল করার আগে সমস্ত লজিককে বোঝায় {}

পরীক্ষা ক্ষেত্রে

আপনি যদি এটি চালান:

<?
    $array = Array(
        'foo' => 1,
        'bar' => 2
    );
    foreach($array as $k=>&$v) {
        $array['baz']=3;
        echo $v." ";
    }
    print_r($array);
?>

আপনি এই আউটপুট পাবেন:

1 2 3 Array
(
    [foo] => 1
    [bar] => 2
    [baz] => 3
)

যার মানে এটি সংশোধন গ্রহণ করেছে এবং এটির মাধ্যমে চলে গেছে কারণ এটি "সময়" সংশোধন করা হয়েছে। কিন্তু আপনি যদি এটি করেন:

<?
    $array = Array(
        'foo' => 1,
        'bar' => 2
    );
    foreach($array as $k=>&$v) {
        if ($k=='bar') {
            $array['baz']=3;
        }
        echo $v." ";
    }
    print_r($array);
?>

তুমি পাবে:

1 2 Array
(
    [foo] => 1
    [bar] => 2
    [baz] => 3
)

যার অর্থ হল অ্যারে সংশোধন করা হয়েছিল, কিন্তু foreachইতিমধ্যেই যখন এটি অ্যারের শেষ উপাদানটিতে ছিল তখন আমরা এটি সংশোধন করেছি , এটি এখন "লুপ" না করার সিদ্ধান্ত নিয়েছে, এবং যদিও আমরা নতুন উপাদান যুক্ত করেছি, আমরা এটি "খুব দেরী" এবং এটি যুক্ত করেছি মাধ্যমে looped ছিল না।

বিস্তারিত ব্যাখ্যা পিএইচপি 'foreach' আসলে কিভাবে কাজ করে পড়তে পারেন ? যা এই আচরণ পিছনে অভ্যন্তরীণ ব্যাখ্যা।


পিএইচপি ম্যানুয়াল দ্বারা সরবরাহিত ডকুমেন্টেশন অনুযায়ী।

প্রতিটি পুনরাবৃত্তির উপর, বর্তমান উপাদানটির মান $ v কে বরাদ্দ করা হয় এবং অভ্যন্তরীণ
অ্যারে পয়েন্টারটি এক দ্বারা উন্নত হয় (তাই পরবর্তী পুনরাবৃত্তিতে, আপনি পরবর্তী উপাদানটি দেখবেন)।

তাই আপনার প্রথম উদাহরণ অনুযায়ী:

$array = ['foo'=>1];
foreach($array as $k=>&$v)
{
   $array['bar']=2;
   echo($v);
}

$arrayশুধুমাত্র একক উপাদান আছে, তাই ফোরাম এক্সিকিউশন অনুযায়ী, 1 বরাদ্দ করা হয়েছে $vএবং এটি পয়েন্টার সরানোর জন্য অন্য কোন উপাদান নেই

কিন্তু আপনার দ্বিতীয় উদাহরণে:

$array = ['foo'=>1, 'bar'=>2];
foreach($array as $k=>&$v)
{
   $array['baz']=3;
   echo($v);
}

$arrayদুটি উপাদান আছে, তাই এখন $ অ্যারের শূন্য সূচকগুলি মূল্যায়ন করে এবং পয়েন্টারটিকে একের মধ্যে সরান। লুপ প্রথম পুনরাবৃত্তি জন্য, $array['baz']=3;রেফারেন্স দ্বারা পাস হিসেবে যোগ করা।


পিএইচপি foreach লুপ Indexed arrays, Associative arraysএবং সঙ্গে ব্যবহার করা যেতে পারে Object public variables

Foreach লুপে, php প্রথম জিনিসটি এটি অ্যারের একটি অনুলিপি তৈরি করে যা এটি পুনরাবৃত্তি করা হয়। পিএইচপি তারপর copyঅ্যারের নতুন এই পরিবর্তে মূল এক। এই নিচের উদাহরণে প্রদর্শিত হয়:

<?php
$numbers = [1,2,3,4,5,6,7,8,9]; # initial values for our array
echo '<pre>', print_r($numbers, true), '</pre>', '<hr />';
foreach($numbers as $index => $number){
    $numbers[$index] = $number + 1; # this is making changes to the origial array
    echo 'Inside of the array = ', $index, ': ', $number, '<br />'; # showing data from the copied array
}
echo '<hr />', '<pre>', print_r($numbers, true), '</pre>'; # shows the original values (also includes the newly added values).

এই ছাড়া, পিএইচপি পাশাপাশি ব্যবহার করার অনুমতি দেয় iterated values as a reference to the original array value। এটি নীচে প্রদর্শিত হয়:

<?php
$numbers = [1,2,3,4,5,6,7,8,9];
echo '<pre>', print_r($numbers, true), '</pre>';
foreach($numbers as $index => &$number){
    ++$number; # we are incrementing the original value
    echo 'Inside of the array = ', $index, ': ', $number, '<br />'; # this is showing the original value
}
echo '<hr />';
echo '<pre>', print_r($numbers, true), '</pre>'; # we are again showing the original value

নোট: এটি original array indexesহিসাবে ব্যবহার করা যাবে না references

উত্স: http://dwellupper.io/post/47/understanding-php-foreach-loop-with-examples





php-internals