Php truyền mảng để hoạt động theo tham chiếu

Hàm [myFunction] lấy một mảng làm tham số [int myNumbers[5]] và lặp qua các phần tử mảng bằng vòng lặp for

Khi hàm được gọi bên trong main[], chúng ta chuyển qua mảng myNumbers, mảng này sẽ xuất ra các phần tử của mảng

Lưu ý rằng khi bạn gọi hàm, bạn chỉ cần sử dụng tên của mảng khi truyền nó dưới dạng đối số myFunction[myNumbers]. Tuy nhiên, cần khai báo đầy đủ mảng trong tham số hàm [int myNumbers[5]]

Trong thời gian dài nhất, tôi đã xem xét rằng các Đối tượng được "chuyển qua tham chiếu" trong PHP và mặc dù điều đó có thể không đúng về mặt kỹ thuật, nhưng đó là một sự đơn giản hóa hữu ích thực hiện công việc trong hầu hết các trường hợp. Vì vậy, nếu bạn đọc tiêu đề và nghĩ "Vâng, đúng là như vậy" thì không cần phải hoảng sợ, mọi thứ có lẽ vẫn ổn, điều đó không có nghĩa là các ứng dụng của bạn sẽ bất ngờ thổi vào mặt bạn. Mặt khác, nếu bạn nghĩ "tham chiếu là cái quái gì vậy?", thì bạn sẽ có một vài điều bất ngờ ẩn giấu trong cơ sở mã của mình và bạn chắc chắn đang ở đúng nơi

Vì vậy, hãy tìm hiểu sâu hơn về các tham chiếu, sau đó chúng ta sẽ xem các đối tượng được truyền qua tham chiếu trông như thế nào, và sau đó tại sao nó thực sự phức tạp hơn thế một chút

Tài liệu tham khảo trong PHP

Tài liệu PHP về các tham chiếu cho chúng ta biết rằng các tham chiếu là "bí danh", có nghĩa là chúng ta có thể nói với PHP rằng chúng ta muốn hai biến trỏ đến cùng một dữ liệu [tài liệu cũng cho chúng ta biết rằng mặc dù chúng không phải là con trỏ, điều này không đặc biệt hữu ích . Ký hiệu để tạo tham chiếu là &

Vì vậy, chúng tôi có thể làm

$a = 'foo'; // $a contains 'foo'
$b = &$a;   // $b is now a reference, or an alias of $a

$b = 'bar' // We're actually changing the content of $a
echo $a    // displays 'bar' [because we just changed the value]
echo $b    // displays 'bar' [because it's still a reference to $a]

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Đây là một điểm kỳ lạ nhỏ, nhưng thực sự không hữu ích trong mã hàng ngày của bạn. Bây giờ, điều hữu ích hơn rất nhiều là bạn có thể chuyển các biến bằng cách tham chiếu đến một hàm, để hàm đó thực sự có thể sửa đổi nội dung của biến bên ngoài phạm vi của chính nó

Điều này được thực hiện bằng cách nối thêm & trước tham số trong khai báo hàm

/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Như bạn có thể thấy, điều này cho phép chúng tôi trả lại một cái gì đó và sửa đổi trực tiếp những gì đã được chuyển đến chức năng. Điều này đặc biệt được sử dụng trong hàm preg_match[] sẽ trả về giá trị true nếu nội dung khớp và chấp nhận tham số $m sẽ được sửa đổi để chứa nội dung khớp. Đây là một tính năng hữu ích, nhưng nó cũng có thể là nguyên nhân gây ra các lỗi khó theo dõi, vì vậy bạn nên thận trọng khi sử dụng tính năng này

Đây là một hình ảnh động đẹp từ bài đăng này minh họa nó một cách độc đáo

Tại sao các đối tượng trông giống như chúng được chuyển qua tham chiếu

Có thể bạn đã đọc ở đâu đó rằng các đối tượng luôn được truyền qua tham chiếu trong PHP. Và nó chắc chắn trông giống như nó

Lấy ví dụ đơn giản này

function doStuff[$object] {
    $object->data = 'newValue';
}

$object = [object]['data' => 'value'];
doStuff[$object];

echo $object->data; // displays 'newValue'

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Như bạn có thể thấy, không có & trong phần khai báo hàm của chúng ta, nhưng giờ đây

/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
1 lại chứa 'newValue' thay vì 'value'. Vì vậy, chức năng đã sửa đổi đối tượng, mà thực sự trông rất giống như nó đã được chuyển qua tham chiếu

Vấn đề với việc sửa đổi các đối tượng

Đây là một ví dụ cụ thể hơn, đó là nguồn gốc của lỗi trong cơ sở mã sản xuất thực tế. Giả sử chúng tôi muốn gửi cho người dùng một email có biên lai cho tháng tới và chúng tôi muốn tiêu đề hiển thị đầu và cuối kỳ theo cách thân thiện với người dùng như "Từ Thứ Năm ngày 1 tháng Bảy đến Thứ Bảy Tháng Bảy . Chúng tôi sẽ tạo một số chức năng để bắt đầu và kết thúc tháng tương ứng với ngày hiện tại và định dạng chúng, sau đó sử dụng kết quả trong một chuỗi [hoặc thực tế hơn là một mẫu]. Nó sẽ trông như thế này

function getFirstDay[$date] {
    return $date->modify['first day of this month']->format['l F j'];
}

function getLastDay[$date] {
    return $date->modify['last day of this month']->format['l F j'];
}

$today = new DateTime['2022-07-15'];
$firstday = getFirstDay[$today];
$lastDay = getLastDay[$today];

$emailTitle = "Your receipt for the period from $firstday to $lastDay";
$emailFooter = "Sent on " .  $today->format["l F j"];

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Tiêu đề sẽ nói
"Biên nhận của bạn trong khoảng thời gian từ Thứ Năm ngày 1 tháng 7 đến Thứ Bảy ngày 31 tháng 7", đó là điều chúng tôi muốn, nhưng chân trang ghi "Đã gửi vào Thứ Bảy ngày 31 tháng 7", đó chắc chắn không phải là điều chúng tôi muốn. Vấn đề là $today đã thực sự bị sửa đổi bởi các hàm khi chúng tôi gọi ->modify[] vào ngày, vì vậy ngay khi chúng tôi sử dụng hàm này vào một ngày, chúng tôi sẽ mất giá trị ban đầu của ngày đó mãi mãi

Có hai cách xung quanh điều này

1- sao chép đối tượng trước khi làm việc với nó

function getFirstDay[$today] {
    $date = clone $today;
    return $date->modify['first day of this month']
        ->format['l F j'];
}

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

2- Sử dụng thư viện như Carbon 2 cung cấp Đối tượng bất biến, về cơ bản là các đối tượng mà mọi phương thức luôn trả về một bản sao thay vì sửa đổi đối tượng hiện tại

Tại sao các đối tượng không thực sự được chuyển qua tham chiếu

Vì vậy, chúng tôi đã thấy rằng có rất nhiều đối tượng giống như các đối tượng được truyền qua tham chiếu và cách tránh các sự cố tiềm ẩn, nhưng toàn bộ điểm của bài đăng này là để chỉ ra rằng chúng không phải như vậy, vì vậy đây là một vài ví dụ để làm cho nó rõ ràng

ví dụ 1. các đối tượng trong một mảng

Giả sử một lớp Người dùng lấy tên của người dùng trong hàm tạo và gán nó cho một thuộc tính tên. Bây giờ hãy xem điều gì sẽ xảy ra nếu chúng ta đặt một số người dùng đó vào một mảng và chuyển nó cho một hàm đặt tên viết hoa cho mỗi phần tử

Class User
{
    public function __construct[public string $name]{}
}

function capitalizeNames[array $users] {
    foreach [$users as $user] {
        $user->name = strtoupper[$user->name];
    }
}

$users = [
    new User['John'],
    new User['Jack'],
];

capitalizeNames[$users];

echo json_encode[$users]; // [{"name":"JOHN"},{"name":"JACK"}]

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Như bạn có thể thấy, mỗi người dùng trong mảng đã được sửa đổi bởi hàm capitalizeNames[]

Chúng tôi không sử dụng tham chiếu, chúng tôi chưa bao giờ chuyển một đối tượng cho hàm vì chúng tôi đã chuyển một mảng [theo giá trị] nên chúng tôi có thể nghĩ rằng mình an toàn. Và mọi đối tượng bên trong mảng đã được sửa đổi

ví dụ 2. Gán một đối tượng cho một biến khác

Bây giờ hãy xem điều gì sẽ xảy ra nếu chúng ta gán một thể hiện của một đối tượng cho một biến mới


$user1 = new User['name'];
$user2 = $user1;

$user1->name = 'Jack';

echo $user1->name; // Jack
echo $user2->name; // Jack

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Vì vậy, về cơ bản, ngay sau khi chúng tôi thực hiện

/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
2, chúng tôi có thể sử dụng cả hai thay thế cho nhau và thay đổi cái này sẽ thay đổi cái kia

Vậy chuyện gì đã xảy ra ?

Vấn đề là một biến không bao giờ "chứa" một đối tượng. Bất cứ khi nào chúng ta gọi

/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
3, PHP sẽ trả về một handle, đây là một tham chiếu. một con trỏ. vâng, hãy gắn bó với tay cầm. Tay cầm đó về cơ bản là một số xác định đối tượng
Bạn thực sự có thể thấy số nhận dạng đối tượng này khi sử dụng
/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
4, đó là số có dấu # phía trước khi kết xuất một đối tượng, ở đây với
/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
5 từ ví dụ trước của chúng ta, chúng ta có thể thấy rằng cả hai đều là cùng một đối tượng vì chúng có cùng một tay cầm

Bạn cũng có thể sử dụng

/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
6 để trả về số nhận dạng đối tượng này

Bất cứ khi nào chúng ta sao chép một biến đối tượng, chuyển nó vào một hàm hoặc đặt nó vào một mảng, chúng ta sẽ không chuyển hoặc sao chép thể hiện của đối tượng, mà chỉ xử lý của nó. Vì vậy, một đối tượng sẽ chỉ tồn tại một lần trừ khi chúng ta sử dụng

/**
 * Decrements a number if it's > 0.
 * Returns true if it was decremented, false if it was already 0 or negative;
 */
function decrement[int &$a] {
    if [$a > 0] {
        $a = $a - 1;
        return true;
    }
    return false;
}

$timeLeft = 10;
$wasModified = decrement[$timeLeft];

echo $timeLeft; // will output 9
7. Giống như một đối tượng trong cuộc sống thực

Phần kết luận

Mặc dù có thể hữu ích khi nghĩ rằng các đối tượng được truyền theo tham chiếu, nhưng tôi nghĩ tốt hơn hết là bạn nên nhớ rằng khi bạn tạo một đối tượng thì chỉ có một thể hiện tồn tại và thứ bạn đang sử dụng không phải là đối tượng mà chỉ đơn giản là một tay cầm.

Tôi hy vọng điều này có thể hữu ích cho ai đó. Ngoài ra, tôi không có bất kỳ nền tảng nào về C và chỉ hiểu mơ hồ về cách điều này thực sự được triển khai trong lõi PHP. Vì vậy, nếu có điều gì đó sai rõ ràng ở trên, vui lòng cho tôi biết trong phần bình luận

Làm cách nào để chuyển mảng theo tham chiếu trong PHP?

Đây là một tập lệnh PHP về cách chuyển mảng làm tham chiếu.

Chủ Đề