อาร์เรย์ใน PHP ถูกคัดลอกเป็นค่าหรืออ้างอิงถึงตัวแปรใหม่และเมื่อส่งผ่านไปยังฟังก์ชั่นหรือไม่


259

1) เมื่ออาร์เรย์ถูกส่งผ่านเป็นอาร์กิวเมนต์ไปยังเมธอดหรือฟังก์ชันมันถูกส่งผ่านโดยการอ้างอิงหรือตามค่าหรือไม่

2) เมื่อกำหนดอาเรย์ให้กับตัวแปรตัวแปรใหม่อ้างอิงถึงอาเรย์ดั้งเดิมหรือเป็นสำเนาใหม่หรือไม่?
เกี่ยวกับการทำสิ่งนี้:

$a = array(1,2,3);
$b = $a;

คือ$bการอ้างอิงถึง$a?


ดูที่When-
do

3
@MarlonJerezIsla: ดูเหมือนว่า Array จะถูกโคลนเฉพาะเมื่อคุณแก้ไขภายในฟังก์ชัน ยังคงมาจากภาษาอื่นดูเหมือนว่าจะแปลก
276648

คำตอบ:


276

สำหรับส่วนที่สองของคำถามของคุณให้ดูหน้าอาร์เรย์ของคู่มือซึ่งระบุ(การอ้างอิง) :

การกำหนดอาร์เรย์มักเกี่ยวข้องกับการคัดลอกค่า ใช้ตัวดำเนินการอ้างอิงเพื่อคัดลอกอาร์เรย์โดยอ้างอิง

และตัวอย่างที่ได้รับ:

<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
             // $arr1 is still array(2, 3)

$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same
?>


สำหรับส่วนแรกวิธีที่ดีที่สุดที่จะแน่ใจคือลอง ;-)

ลองพิจารณาตัวอย่างของรหัสนี้:

function my_func($a) {
    $a[] = 30;
}

$arr = array(10, 20);
my_func($arr);
var_dump($arr);

มันจะให้ผลลัพธ์นี้:

array
  0 => int 10
  1 => int 20

ซึ่งบ่งชี้ว่าฟังก์ชั่นไม่ได้แก้ไขอาร์เรย์ "นอก" ที่ถูกส่งผ่านเป็นพารามิเตอร์: มันถูกส่งเป็นสำเนาและไม่ใช่การอ้างอิง

หากคุณต้องการให้มันผ่านการอ้างอิงคุณจะต้องแก้ไขฟังก์ชั่นด้วยวิธีนี้:

function my_func(& $a) {
    $a[] = 30;
}

และผลลัพธ์จะกลายเป็น:

array
  0 => int 10
  1 => int 20
  2 => int 30

ในขณะนี้อาร์เรย์ได้ผ่าน "โดยอ้างอิง"


อย่าลังเลที่จะอ่านส่วนข้อมูลอ้างอิงที่อธิบายในคู่มือ: ควรตอบคำถามของคุณ ;-)


สิ่งที่เกี่ยวกับบางสิ่งเช่น $ a = & $ this-> a ตอนนี้เป็น $ a สำหรับการอ้างอิง & this-> a หรือไม่
แฟรงค์

1
ในขณะที่คุณกำลังใช้&ใช่มันควร - ดูphp.net/manual/en/…
Pascal MARTIN

1
วัวศักดิ์สิทธิ์ฉันไม่อยากจะเชื่อเลยว่านี่เป็นปัญหาที่ฉันมี ... นี่ควรจะเป็นบทเรียนอ่านคู่มือการ
บุกเสมอ

2
สวัสดี Pascal ฉันพบคำตอบของ Kosta Kontos ดูเหมือนว่าจะแม่นยำมากขึ้น ฉันทำแบบทดสอบอย่างง่าย ๆ เพื่อยืนยันการค้นพบของเขาgist.github.com/anonymous/aaf845ae354578b74906คุณสามารถแสดงความคิดเห็นเกี่ยวกับการค้นพบของเขาได้หรือไม่?
Cheok Yan Cheng

1
นี่คือปัญหาที่ฉันมีด้วย: คิดว่ามันเป็นสิ่งที่แปลกเกี่ยวกับอาร์เรย์ที่ซ้อนกัน แต่จริงๆแล้วมันเป็นเพียงแค่วิธีการทำงานของอาร์เรย์ใน PHP
Jeremy List

120

สำหรับคำถามแรกของคุณอาร์เรย์จะถูกส่งผ่านโดยการอ้างอิงจนกว่าจะมีการแก้ไขภายในวิธีการ / ฟังก์ชั่นที่คุณโทร หากคุณพยายามที่จะปรับเปลี่ยนอาร์เรย์ภายในวิธีการ / ฟังก์ชั่นการทำสำเนาของมันจะถูกสร้างขึ้นก่อนแล้วจึงทำการคัดลอกเฉพาะการแก้ไข สิ่งนี้ทำให้ดูเหมือนกับว่าอาร์เรย์ถูกส่งผ่านโดยค่าเมื่อในความเป็นจริงมันไม่ได้

ตัวอย่างเช่นในกรณีแรกแม้ว่าคุณจะไม่ได้กำหนดฟังก์ชั่นของคุณเพื่อรับ $ my_array โดยการอ้างอิง (โดยใช้ตัวอักษร & ในการกำหนดพารามิเตอร์) แต่ก็ยังได้รับการส่งผ่านโดยการอ้างอิง (เช่น: คุณไม่เสียหน่วยความจำ พร้อมสำเนาที่ไม่จำเป็น)

function handle_array($my_array) {  

    // ... read from but do not modify $my_array
    print_r($my_array);

    // ... $my_array effectively passed by reference since no copy is made
}

อย่างไรก็ตามหากคุณแก้ไขอาเรย์จะมีการคัดลอกอาเรย์ก่อน (ซึ่งใช้หน่วยความจำมากกว่า แต่จะไม่ได้รับผลกระทบจากอาเรย์เดิม)

function handle_array($my_array) {

    // ... modify $my_array
    $my_array[] = "New value";

    // ... $my_array effectively passed by value since requires local copy
}

FYI - สิ่งนี้เรียกว่า "lazy copy" หรือ "copy-on-write"


8
นี่เป็นข้อมูลที่น่าสนใจอย่างยิ่ง! ดูเหมือนว่ามันเป็นเรื่องจริง แต่ฉันหาเอกสารทางการไม่ได้ที่สนับสนุนข้อเท็จจริงนี้ เราต้องทราบด้วยว่าเวอร์ชันของ PHP รองรับแนวคิดการทำสำเนาแบบขี้เกียจ ใครมีข้อมูลเพิ่มเติม
Mario Awad

8
อัปเดตพบเอกสารบางอย่างเป็นทางการยังคงต้องค้นหาเวอร์ชันของ PHP ที่รองรับการทำสำเนาแบบขี้เกียจ (เรียกว่า "copy on write" ในคู่มือ): php.net/manual/en/internals2.variables.intro.php
Mario Awad

7
นี่เป็นการตัดสินใจในการนำไปใช้จริงของเครื่องเสมือน PHP ไม่ใช่ส่วนหนึ่งของภาษา แต่จริงๆแล้วโปรแกรมเมอร์ไม่สามารถมองเห็นได้ แนะนำให้ใช้การคัดลอกบนการเขียนด้วยเหตุผลด้านประสิทธิภาพ แต่การใช้งานที่คัดลอกทุกแถวไม่มีความแตกต่างจากมุมมองของโปรแกรมเมอร์ดังนั้นเราจึงสามารถพูดได้ว่าความหมายภาษาระบุค่าแบบส่งต่อค่า
Superfly

14
@ Superfly มันสร้างความแตกต่างอย่างแน่นอนเมื่อฉันต้องการที่จะรู้ว่าฉันสามารถส่งผ่านอาร์เรย์ 100MB ของฉันผ่านฟังก์ชั่นมากมายโดยไม่ต้องใช้หน่วยความจำหมด! คุณอาจจะถูกต้องที่จะเรียกความหมายของ pass-by-value แต่การละทิ้งความคิดดังกล่าวมากกว่าคำศัพท์ "รายละเอียดการใช้งาน" ที่กล่าวถึงในที่นี้ไม่สำคัญต่อโปรแกรมเมอร์ PHP ในโลกแห่งความเป็นจริง
Mark Amery

3
ยังมีสิ่งแปลกประหลาดอีกอย่างหนึ่งที่ทำให้การตระหนักถึงการคัดลอกเมื่อเขียนสำคัญยิ่งขึ้นเมื่อคิดถึงประสิทธิภาพ คุณอาจคิดว่าการส่งผ่านอาร์เรย์โดยการอ้างอิงช่วยประหยัดหน่วยความจำเปรียบเทียบกับการส่งผ่านค่า (ถ้าคุณไม่รู้เกี่ยวกับการคัดลอกเมื่อเขียน) แต่จริง ๆ แล้วมันสามารถมีผลตรงกันข้าม หากอาร์เรย์ภายหลังผ่านค่า (ตามรหัสบุคคลของคุณเองหรือ 3), PHP แล้วมีการทำสำเนาแบบเต็มรูปแบบหรือไม่สามารถติดตามจำนวนการอ้างอิง! เพิ่มเติมได้ที่นี่: stackoverflow.com/questions/21974581/…
Dan King

80

TL; DR

ก) วิธีการ / ฟังก์ชั่นเพียงอ่านอาร์กิวเมนต์อาเรย์ => การอ้างอิง (ภายใน) โดยนัย
b) วิธีการ / ฟังก์ชั่นปรับเปลี่ยนอาเรย์อาร์กิวเมนต์ => ค่า
ค) เมธอด / ฟังก์ชั่นอาเรย์จะถูกทำเครื่องหมายเป็นการอ้างอิงอย่างชัดเจน => การอ้างอิงที่ชัดเจน (ผู้ใช้ที่ดิน)

หรือสิ่งนี้:
- ไม่ใช่พารามิเตอร์แอมเปอร์แซนด์และพารามิเตอร์ : ผ่านโดยการอ้างอิง; การดำเนินการเขียนแก้ไขสำเนาใหม่ของอาเรย์คัดลอกซึ่งถูกสร้างขึ้นในการเขียนครั้งแรก;
- อาร์เรย์เครื่องหมายแอมเปอร์แซนด์ : ผ่านการอ้างอิง; การดำเนินการเขียนเปลี่ยนอาร์เรย์เดิม

ข้อควรจำ - PHP ทำการคัดลอกค่าเมื่อคุณเขียนไปยังพารามิเตอร์ที่ไม่ใช่เครื่องหมายและแถวลำดับ นั่นคือสิ่งที่copy-on-writeหมายถึง ฉันชอบที่จะแสดงให้คุณเห็นที่มาของพฤติกรรมนี้ แต่ก็น่ากลัวมาก ดีกว่าการใช้xdebug_debug_zval ()

Pascal MARTIN ถูกต้อง Kosta Kontos ยิ่งกว่านั้นอีก

ตอบ

มันขึ้นอยู่กับ.

รุ่นยาว

ฉันคิดว่าฉันเขียนมันลงไปเพื่อตัวเอง ฉันควรมีบล็อกหรืออะไรซักอย่าง ...

เมื่อใดก็ตามที่ผู้คนพูดถึงการอ้างอิง (หรือพอยน์เตอร์สำหรับเรื่องนั้น) พวกเขามักจะจบลงด้วยอาการท้องอืด (ดูที่หัวข้อนี้!)
PHP เป็นภาษาที่น่านับถือฉันคิดว่าฉันควรจะเพิ่มความสับสน (แม้ว่านี่จะเป็นบทสรุปของคำตอบข้างต้น) เพราะถึงแม้ว่าคนสองคนจะพูดถูกในเวลาเดียวกัน แต่คุณก็ยังดีกว่าที่จะตอบโต้ด้วยคำตอบเดียว

ปิดครั้งแรกที่คุณควรรู้ว่าคุณไม่ได้เป็นคนอวดรู้ถ้าคุณไม่ได้คำตอบในลักษณะที่เป็นสีขาวดำและสี สิ่งต่าง ๆ มีความซับซ้อนมากกว่า "ใช่ / ไม่ใช่"

อย่างที่คุณจะเห็นสิ่งทั้งหมดโดยค่า / โดยอ้างอิงมีความเกี่ยวข้องมากกับสิ่งที่คุณกำลังทำกับอาร์เรย์ที่ในขอบเขตวิธีการ / ฟังก์ชั่นของคุณ: อ่านมันหรือแก้ไขมันได้หรือไม่

PHP บอกว่าอะไร? (aka "เปลี่ยนปัญญา")

คู่มือบอกว่านี่ (ผมขอย้ำ):

โดยค่าเริ่มต้นอาร์กิวเมนต์ของฟังก์ชันจะถูกส่งผ่านตามค่า (เพื่อให้ถ้าค่าของอาร์กิวเมนต์ภายในฟังก์ชันนั้นเปลี่ยนไปจะไม่ได้รับการเปลี่ยนแปลงนอกฟังก์ชัน) ในการอนุญาตให้ฟังก์ชั่นในการแก้ไขข้อโต้แย้งของพวกเขาจะต้องผ่านอ้างอิง

เมื่อต้องการให้อาร์กิวเมนต์ของฟังก์ชันผ่านการอ้างอิงเสมอให้ใส่เครื่องหมาย & (&) ไปยังชื่ออาร์กิวเมนต์ในนิยามฟังก์ชัน

เท่าที่ฉันสามารถบอกได้เมื่อผู้เขียนโปรแกรมขนาดใหญ่จริงจังซื่อสัตย์ต่อพระเจ้าพูดถึงการอ้างอิงพวกเขามักจะพูดถึงการเปลี่ยนแปลงค่าของการอ้างอิงนั้น hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"และนั่นคือสิ่งที่พูดถึงคู่มือเกี่ยวกับ:

มีอีกกรณีที่พวกเขาไม่ได้เอ่ยถึง: ถ้าฉันไม่เปลี่ยนแปลงอะไร - แค่อ่าน?
ถ้าคุณส่งอาเรย์ไปยังเมธอดที่ไม่ทำเครื่องหมายการอ้างอิงอย่างชัดเจนและเราจะไม่เปลี่ยนอาเรย์นั้นในขอบเขตฟังก์ชั่น เช่น:

<?php
function readAndDoStuffWithAnArray($array) 
{
    return $array[0] + $array[1] + $array[2];
}

$x = array(1, 2, 3);

echo readAndDoStuffWithAnArray($x);

อ่านต่อไปเพื่อนนักเดินทางของฉัน

PHP ทำอะไรได้จริง? (aka "หน่วยความจำที่ชาญฉลาด")

โปรแกรมเมอร์ตัวใหญ่และจริงจังคนเดียวกันเมื่อพวกเขาจริงจังมากขึ้นพวกเขาพูดถึง "การเพิ่มประสิทธิภาพหน่วยความจำ" ในส่วนที่เกี่ยวกับการอ้างอิง PHP ก็เช่นกัน เพราะPHP is a dynamic, loosely typed language, that uses copy-on-write and reference countingนั่นคือเหตุผลว่าทำไม

มันจะไม่เหมาะที่จะส่งอาร์เรย์ขนาดใหญ่ไปยังฟังก์ชั่นต่างๆและ PHP เพื่อทำสำเนาของพวกเขา (นั่นคือสิ่งที่ "pass-by-value" ทำ)

<?php

// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from your RAM
$x = array_fill(0, 10000, 1); 

// pass by value, right? RIGHT?
function readArray($arr) { // <-- a new symbol (variable) gets created here
    echo count($arr); // let's just read the array
}

readArray($x);

ทีนี้, ถ้านี่คือการส่งผ่านตามค่าจริง, เราอยากได้ 3mb + RAM สักหน่อย, เพราะมีสองชุดของอาร์เรย์, จริงไหม?

ไม่ถูกต้อง. ตราบใดที่เราไม่เปลี่ยน$arrตัวแปรที่อ้างอิงหน่วยความจำที่ชาญฉลาด คุณแค่ไม่เห็นมัน นั่นเป็นเหตุผลที่ PHP กล่าวถึง การอ้างอิงผู้ใช้เมื่อพูดถึง&$someVarเพื่อแยกแยะความแตกต่างระหว่างภายในและชัดเจน (กับแอมเปอร์แซนด์)

ข้อเท็จจริง

ดังนั้น, when an array is passed as an argument to a method or function is it passed by reference?

ฉันมากับสาม (ใช่สาม) กรณี:
a) วิธีการ / ฟังก์ชั่นเพียงอ่านอาร์กิวเมนต์อาเรย์
ข) วิธีการ / ฟังก์ชั่นปรับเปลี่ยนอาร์กิวเมนต์อาเรย์
ค) วิธีการ / ฟังก์ชั่นการโต้แย้งอาร์เรย์ถูกทำเครื่องหมายไว้อย่างชัดเจน เครื่องหมาย)


ก่อนอื่นมาดูกันว่าหน่วยความจำที่อาร์เรย์กินจริง (ทำงานที่นี่ ):

<?php
$start_memory = memory_get_usage();
$x = array_fill(0, 10000, 1);
echo memory_get_usage() - $start_memory; // 1331840

ไบต์นั้นมากมาย ยิ่งใหญ่

a) วิธีการ / ฟังก์ชั่นอ่านอาร์กิวเมนต์อาเรย์เท่านั้น

ทีนี้มาสร้างฟังก์ชั่นที่อ่านอาเรย์ที่กล่าวมาเป็นอาร์กิวเมนต์เท่านั้นและเราจะเห็นว่าหน่วยความจำที่ตรรกะใช้ในการอ่านมีเท่าไหร่:

<?php

function printUsedMemory($arr) 
{
    $start_memory = memory_get_usage();

    count($arr);       // read
    $x = $arr[0];      // read (+ minor assignment)
    $arr[0] - $arr[1]; // read

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1); // this is 1331840 bytes
printUsedMemory($x);

อยากเดาไหม ฉันได้ 80! ดูตัวเอง นี่คือส่วนที่คู่มือ PHP ละเว้น หาก$arrพารามิเตอร์ถูกส่งผ่านตามค่าจริงคุณจะเห็นบางสิ่งที่คล้ายคลึงกับ1331840ไบต์ ดูเหมือนว่า$arrจะมีพฤติกรรมเหมือนเป็นข้อมูลอ้างอิงใช่ไหม นั่นเป็นเพราะมันเป็นข้อมูลอ้างอิง - ข้อมูลภายใน

b) วิธีการ / ฟังก์ชั่นปรับเปลี่ยนอาร์กิวเมนต์อาเรย์

ตอนนี้เรามาเขียนถึงพารามิเตอร์นั้นแทนที่จะอ่านจาก:

<?php

function printUsedMemory($arr)
{
    $start_memory = memory_get_usage();

    $arr[0] = 1; // WRITE!

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

อีกครั้งดูตัวเองแต่สำหรับผมที่สวยใกล้เคียงกับการ 1331840. ดังนั้นในกรณีนี้อาร์เรย์เป็น$arrจริงจะถูกคัดลอกไป

c) อาร์กิวเมนต์วิธีการ / ฟังก์ชั่นมีการทำเครื่องหมายอย่างชัดเจนว่าเป็นข้อมูลอ้างอิง (มีเครื่องหมายและ)

ตอนนี้เรามาดูวิธีหน่วยความจำมากดำเนินการเขียนไปยังข้อมูลอ้างอิงที่ชัดเจนใช้เวลา (ระยะที่นี่ ) - โน้ตเครื่องหมายในลายเซ็นของฟังก์ชั่น:

<?php

function printUsedMemory(&$arr) // <----- explicit, user-land, pass-by-reference
{
    $start_memory = memory_get_usage();

    $arr[0] = 1; // WRITE!

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

เดิมพันของฉันคือคุณจะได้รับสูงสุด 200! ดังนั้นกินนี้ประมาณเป็นหน่วยความจำมากที่สุดเท่าที่อ่านจากที่ไม่ใช่เครื่องหมายพระราม


ช่วยฉันสองสามชั่วโมงในการแก้ปัญหาการรั่วไหลของหน่วยความจำ!
Ragen Dazs

2
Kosta Kontos: นี่เป็นคำถามสำคัญที่คุณควรทำเครื่องหมายว่าเป็นคำตอบที่ยอมรับได้ ที่กล่าวถึง @nevvermind: เรียงความที่ดี แต่โปรดรวมส่วน TL; DR อันดับต้น ๆ ไว้ด้วย
พัฒนา AVID

1
@nevvermind: ฉันไม่ใช่อักษรย่อตัวย่อต่างหลักคือข้อสรุปมักจะปรากฏที่ท้ายบทความขณะที่ TL; DR ปรากฏเป็นบรรทัดแรกสำหรับผู้ที่ต้องการคำตอบสั้น ๆ แทนที่จะต้องผ่านการวิเคราะห์ที่ยาวนาน . งานวิจัยของคุณดีและนี่ไม่ใช่การวิจารณ์เพียง $ 00.02 ของฉัน
AVIDeveloper

1
คุณถูก. ฉันได้ข้อสรุปที่ด้านบน แต่ฉันยังคงชอบคนที่จะหยุดการขี้เกียจอ่านในสิ่งที่ทั้งก่อนที่จะถึงข้อสรุปใดการเลื่อนนั้นง่ายเกินไปสำหรับเราที่จะเปลี่ยนลำดับของสิ่งต่าง ๆ
nevvermind

1
ฉันเดา PHP มีอากาศปีที่มีประสิทธิภาพมากขึ้นในภายหลังเพราะตัวอย่าง Codepad ของคุณให้ตัวเลขที่ต่ำกว่ามาก :)
drzaus

14

โดยค่าเริ่มต้น

  1. จะถูกส่งผ่านค่าพื้นฐาน ไม่น่าจะเป็นจาวาสตริงเป็นพื้นฐานใน PHP
  2. อาร์เรย์ของดั้งเดิมจะถูกส่งผ่านตามค่า
  3. วัตถุถูกส่งผ่านโดยการอ้างอิง
  4. อาร์เรย์ของวัตถุถูกส่งผ่านโดยค่า (อาร์เรย์) แต่แต่ละวัตถุจะถูกส่งผ่านโดยการอ้างอิง

    <?php
    $obj=new stdClass();
    $obj->field='world';
    
    $original=array($obj);
    
    
    function example($hello) {
        $hello[0]->field='mundo'; // change will be applied in $original
        $hello[1]=new stdClass(); // change will not be applied in $original
        $
    }
    
    example($original);
    
    var_dump($original);
    // array(1) { [0]=> object(stdClass)#1 (1) { ["field"]=> string(5) "mundo" } } 

หมายเหตุ: เป็นการเพิ่มประสิทธิภาพทุกค่าเดียวจะถูกส่งผ่านเป็นข้อมูลอ้างอิงจนกว่าจะถูกแก้ไขภายในฟังก์ชัน หากมีการแก้ไขและค่าถูกส่งผ่านโดยอ้างอิงก็จะถูกคัดลอกและคัดลอกจะถูกปรับเปลี่ยน


4
คำตอบนี้ควร +1 ขึ้นไปด้านบน มันมี gotcha ที่คลุมเครือซึ่งคำตอบอื่น ๆ ไม่ได้กล่าวถึง: "4 - อาร์เรย์ของวัตถุถูกส่งผ่านตามค่า (อาร์เรย์) แต่แต่ละวัตถุจะถูกส่งผ่านโดยการอ้างอิง" ฉันเกาหัวเพราะสิ่งนั้น!
augustin

@magallanes ที่ดีควรได้รับการจัดอันดับเป็นอันดับแรกสำหรับฉันเช่นกันคุณชี้แจงปัญหาของอาร์เรย์วัตถุที่ฉันมี มีวิธีการแก้ไขวัตถุในอาเรย์เพียงหนึ่งในสองตัวแปรอาเรย์ (ต้นฉบับและคัดลอก)?
fede72bari

5

เมื่ออาเรย์ถูกส่งผ่านไปยังเมธอดหรือฟังก์ชั่นใน PHP มันจะถูกส่งผ่านโดยค่าเว้นแต่คุณจะผ่านมันอย่างชัดเจนโดยการอ้างอิงเช่น:

function test(&$array) {
    $array['new'] = 'hey';
}

$a = $array(1,2,3);
// prints [0=>1,1=>2,2=>3]
var_dump($a);
test($a);
// prints [0=>1,1=>2,2=>3,'new'=>'hey']
var_dump($a);

ในคำถามที่สองของคุณ$bไม่ได้มีการอ้างอิงถึงแต่คัดลอกของ $a$a

เหมือนตัวอย่างแรกคุณสามารถอ้างอิงได้$aโดยทำดังต่อไปนี้:

$a = array(1,2,3);
$b = &$a;
// prints [0=>1,1=>2,2=>3]
var_dump($b);
$b['new'] = 'hey';
// prints [0=>1,1=>2,2=>3,'new'=>'hey']
var_dump($a);

1

กระทู้นี้ค่อนข้างเก่า แต่นี่เป็นสิ่งที่ฉันเพิ่งเจอ:

ลองรหัสนี้:

$date = new DateTime();
$arr = ['date' => $date];

echo $date->format('Ymd') . '<br>';
mytest($arr);
echo $date->format('Ymd') . '<br>';

function mytest($params = []) {
    if (isset($params['date'])) {
        $params['date']->add(new DateInterval('P1D'));
    }
}

http://codepad.viper-7.com/gwPYMw

โปรดทราบว่าไม่มีแอมป์สำหรับพารามิเตอร์ $ params และยังคงเปลี่ยนค่าของ $ arr ['date'] สิ่งนี้ไม่ตรงกับคำอธิบายอื่น ๆ ทั้งหมดที่นี่และสิ่งที่ฉันคิดจนถึงตอนนี้

ถ้าฉันคัดลอกออบเจ็กต์ $ params ['date'] วันที่ที่เอาท์พุทที่ 2 ยังคงเหมือนเดิม หากฉันเพิ่งตั้งเป็นสตริงมันจะไม่ส่งผลกระทบใด ๆ


3
อาร์เรย์ถูกคัดลอกแล้ว แต่ไม่ใช่สำเนาลึก ซึ่งหมายความว่าค่าดั้งเดิมเช่นตัวเลขและสตริงจะถูกคัดลอกไปยัง $ param แต่สำหรับวัตถุการอ้างอิงจะถูกคัดลอกแทนวัตถุที่ถูกโคลน $ arr ถือการอ้างอิงถึง $ date และเป็น $ params ที่คัดลอกแล้ว ดังนั้นเมื่อคุณเรียกใช้ฟังก์ชันบน $ params ['date'] ที่เปลี่ยนค่าของมันคุณจะเปลี่ยน $ arr ['date'] และ $ date เมื่อคุณตั้งค่า $ params ['date'] เป็นสตริงคุณเพียงแค่แทนที่การอ้างอิงของ $ params เป็น $ date ด้วยสิ่งอื่น
ejegg

1

ในการขยายคำตอบหนึ่งคำสั่งนั้นอาร์เรย์ย่อยของอาร์เรย์หลายมิติจะถูกส่งผ่านตามค่าเว้นแต่ว่าจะผ่านการอ้างอิงอย่างชัดเจน

<?php
$foo = array( array(1,2,3), 22, 33);

function hello($fooarg) {
  $fooarg[0][0] = 99;
}

function world(&$fooarg) {
  $fooarg[0][0] = 66;
}

hello($foo);
var_dump($foo); // (original array not modified) array passed-by-value

world($foo);
var_dump($foo); // (original array modified) array passed-by-reference

ผลลัพธ์คือ:

array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [1]=>
  int(22)
  [2]=>
  int(33)
}
array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(66)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [1]=>
  int(22)
  [2]=>
  int(33)
}

0

ในอาร์เรย์ PHP จะถูกส่งผ่านไปยังฟังก์ชั่นโดยค่าเริ่มต้นเว้นแต่คุณจะผ่านพวกเขาอย่างชัดเจนโดยการอ้างอิงตามตัวอย่างต่อไปนี้แสดง:

$foo = array(11, 22, 33);

function hello($fooarg) {
  $fooarg[0] = 99;
}

function world(&$fooarg) {
  $fooarg[0] = 66;
}

hello($foo);
var_dump($foo); // (original array not modified) array passed-by-value

world($foo);
var_dump($foo); // (original array modified) array passed-by-reference

นี่คือผลลัพธ์:

array(3) {
  [0]=>
  int(11)
  [1]=>
  int(22)
  [2]=>
  int(33)
}
array(3) {
  [0]=>
  int(66)
  [1]=>
  int(22)
  [2]=>
  int(33)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.