هل أحتاج إلى استخدام ampersand في PHP 5.5.x وما فوق بعد الآن؟

StackOverflow https://stackoverflow.com/questions/19847781

سؤال

أحصل على إشارات مختلطة في كل مكان.

هل أستخدم ampersand لتمرير المتغيرات بالرجوع إليها أم لا؟

يبدو أن الرابط التالي يخبرني أنه تم إهماله ولم يعد ضروريًا:
http://gtk.php.net/manual/en/html/tutorials/tutorials.changes.references.html

لكن خيوط مثل هذه تجعلني أتساءل:
تم إهمال وقت الاتصال بالمرجع؟
PHP و Ampersand

اسمحوا لي أن العبارة سؤالي كمثال.

إذا قمت بعمل وظيفة ، باستخدام PHP 5.5.5:

function recurring_mailer_form($form, $form_state) 
{

}

هل هو نفسه:

function recurring_mailer_form($form, &$form_state) 
{

}

?

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

المحلول

السبب في أن المقالات المختلفة تقول إن أشياء مختلفة هي أنهم يتحدثون عن أنواع مختلفة من المرجع.

الشيء الرئيسي الذي يحدد ما إذا كان ينبغي تمرير المعلمة بالرجوع إليه هو توقيع الوظيفة نفسه ، ولم تتغير أساسيات هذا منذ PHP 4. فكر في هذا المثال:

function foo( $by_value, &$by_reference ) { /* ... */ }

$a = 1; $b = 2;
foo( $a, $b );

هنا ، المتغير الخارجي $a يتم تمريرها إلى الوظيفة بالقيمة ، كما لو تم تعيينها كـ $by_value = $a; - تغيير الى $by_value لا يمكن أن تؤثر $a. المتغير $b ومع ذلك يتم تمريرها بالتزكية; ؛ تماما مثل تعيين النموذج $by_reference =& $b; هذا يعني أن هناك متغيرًا واحدًا يشير إليه اسمين ، وأي مهمة لأحدها ستكون بمثابة مهمة لكليهما.

إذا قمت بتمرير قيمة "عادية" (سلسلة أو رقم أو صفيف) حسب القيمة ، يتم نسخ قيمتها فقط إلى المتغير الجديد. اعتبارا من PHP 5: إذا قمت بتمرير كائن حسب القيمة ، فإن شيئًا مختلفًا قليلاً يحدث - "القيمة" المنقولة هي مجرد مؤشر إلى نفس الكائن. هذا يعني أنه إذا $a كان كائنًا ، يمكنك الاتصال $by_value->some_property = 42; و $a->some_property سيكون أيضا 42. ومع ذلك ، إذا قمت بتعيين بعض القيمة الجديدة ل $by_value, ، لا يزال لا يؤثر $a.

حتى PHP 5.4, ، كان هناك إضافي طريقة لتمرير المعلمة بالرجوع إليها ، والتي كانت "فرض" السلوك المرجعي في وقت الاتصال. هذا يعني أنه يمكنك الكتابة foo(&$a, &$b); و "التقاط" التغييرات التي تم إجراؤها $by_value داخل foo() وظيفة. كان الاعتماد على هذا عمومًا فكرة سيئة ، وبالتالي تمت إزالته. (لقد هبط في 5.4 لأنه كان مخصصًا للإزالة في PHP 6 ، ولكن تم وضع هذا المشروع على عقد غير محدد ، مع التغييرات الأصغر في 5.3 و 5.4).

أخيرًا ، يمكن للوظائف إرجاع متغير بالرجوع إليه (كما ناقش في الدليل هنا). هذا أمر غامض بعض الشيء ، لأنه يتطلب منك بالفعل أن تضعه & في اثنين الأماكن: في بداية إعلان الوظيفة ، ليقول ذلك return يجب أن تعني "إرجاع هذا المرجع المتغير" وليس "إرجاع هذه القيمة" ؛ وفي الكود الذي يطلق عليه ، لتعيين متغير لهذا المرجع ، بدلاً من مجرد نسخ قيمته. إليك مثال سخيف يجمع بين معلمة مرجعية مع عائد مرجعي (لا يتعين على الاثنين أن يجتمعوا ، إنه مجرد مثال):

function &bar(&$some_param) { return $some_param; }
$a = 1;
$b =& bar($a);
// $b and $a now point at the same variable, not just the same value
// it was passed into and out of a function, and assigned to a new variable, 
// but all those operations were by reference

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

نصائح أخرى

لا ليست كذلك.

  • يتم تمرير الكائنات دائمًا تلقائيًا كمراجع (معلومات! انظر أدناه للحصول على معلومات مهمة إضافية!)

  • يجب أن يحدث إعلان المعلمات كمراجع في تعريف الوظيفة:

    function test(&$var) {}
    

    لا في وقت الاتصال به:

    // wrong
    $var = '123';
    test(&$var);
    


إذا قمت بتمرير كائن كالمعتاد ، فيمكنك تغيير حالة الكائن (الخصائص).
افترض أن $obj هو مثال على الفصل TestClass الذي يحتوي على متغير عضو يسمى hello (انقر هنا للحصول على عينة كاملة في ideone.com):

function modify($obj) { $obj->hello = 'world (modified)!'; }

$obj->hello = 'world';
modify($obj);
var_dump($obj->hello);  // outputs "world (modified!)"

يجب أن يكون هذا محطًا ذاتيًا. الآن ، باستخدام نفس الرمز ولكن تعيين قيمة أخرى ل $obj بدلاً من ذلك ، لا يؤدي تعديل حالة الكائن إلى تعديل (→ ideone.com):

function modify($obj) { $obj = 42; }
// ...
var_dump($obj->hello);  // outputs "world"

فقط قبول المعلمة بشكل صريح كمرجع يعطينا القدرة على تغيير محتويات المتغير بالكامل (→ ideone.com):

function modify(&$obj) { $obj = 42; }
// ...
var_dump($obj);         // outputs "42"

لا ، هذه ليست هي نفسها. PHP 5.4+ يكتشف فقط على المكالمة ما إذا كان هناك حاجة إلى المرجع عندما يتم استدعاء الوظيفة عن طريق التحقق من الإعلان.

لذلك لا ، لا يتم إهمالها لأنك تحتاج إلى المشغل المرجعي في إعلان الوظيفة إذا كان هذا هو الاستخدام المقصود.

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