#php
#php
Вопрос:
Я создаю приложение, которое получает с моего сервера список продуктов (например) и отображает их. Я использую PHP и Apache для извлечения списка из базы данных SQL Server (в значительной степени REST API). Когда я создаю массив и кодирую его, я замечаю, что в моем массиве 10 элементов (или больше, в настоящее время я устанавливаю это ограничение для тестирования), и каждый из них является последним.
Я пытался использовать $arr[] = $prod
или array_push($arr, $prod)
, или создать временный массив и объединить их, но результат все тот же. Я также попытался переключиться с macOS Apache на Windows install или Linux one (я думал, что это может быть версия Apache / PHP).
$prod = new StdClass(); $arr = array();
$search = $_GET['search'];
$search = "%$search%";
$sql = "SELECT TOP 10
product, qty
FROM
table
WHERE
product LIKE ?";
$stmt = sqlsrv_prepare( $conn, $sql, array($search));
sqlsrv_execute( $stmt );
$i = 0;
if ( $stmt === false ) {
die( print_r( sqlsrv_errors(), true) );
}
else {
while ( $row=sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) ) {
$prod->mainInfo = $row['product'];
$prod->secondInfo = $row['qty'];
$arr[] = $prod;
}
}
http_response_code(200);
echo json_encode($arr);
Результатом является что-то среди этих строк (есть и другие строки, но я включаю только три, поскольку это не имеет значения):
[
{
"mainInfo": "product3",
"secondInfo": "qty3"
},
{
"mainInfo": "product3",
"secondInfo": "qty3"
},
{
"mainInfo": "product3",
"secondInfo": "qty3"
}
]
Если есть три продукта, которые я загружаю. Третий продукт отображается во всех элементах массива. Это должно быть что-то вроде этого:
[
{
"mainInfo": "product1",
"secondInfo": "qty1"
},
{
"mainInfo": "product2",
"secondInfo": "qty2"
},
{
"mainInfo": "product3",
"secondInfo": "qty3"
}
]
Комментарии:
1. Объекты обновляются по ссылке. Попробуйте создавать новый продукт для каждой итерации или, по крайней мере, использовать
cone $product
Ответ №1:
Объекты в php всегда обрабатываются по ссылке. Итак, каждый раз, когда вы изменяете $prod
в одном месте, оно изменяется везде. Чтобы избежать этого, clone
создайте объект и работайте с клонированной копией:
while ( $row=sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) ) {
$newProd = clone $prod;
$newProd->mainInfo = $row['product'];
$newProd->secondInfo = $row['qty'];
$arr[] = $newProd;
}
Комментарии:
1. Спасибо за ваш быстрый ответ! Не могли бы вы немного объяснить, почему я должен клонировать новый объект, а не перемещаться
$prod = new StdClass();
внутри цикла, как упоминал @trincot? Это более эффективно?2. Это просто разные подходы. Клонирование может быть полезно, когда у вас есть какой-то объект с уже заполненными свойствами и вы не хотите каждый раз создавать новый объект и заполнять эти свойства снова и снова. В случае простого объекта нет существенной разницы между клонированием объекта и созданием нового.
Ответ №2:
Объекты обновляются по ссылке.
Это означает, что значения будут динамически меняться по мере изменения объекта, даже если вы помещали объект в массив в прошлом. По сути, вы изменяете один и тот же объект снова и снова.
Вы можете создать новый экземпляр объекта с помощью new
или clone
while ( $row=sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) ) {
$_prod = clone $prod; //copy the object
$_prod ->mainInfo = $row['product'];
$_prod ->secondInfo = $row['qty'];
$arr[] = $_prod;
}
Ответ №3:
Вы изменяете один и тот же объект снова и снова. Даже когда он уже был добавлен в массив, это влияет на этот единственный объект. А ваши массивы просто получают несколько ссылок на один и тот же объект.
Чтобы решить эту проблему, убедитесь, что $prod
это новый объект в каждом начале итерации.
Итак, переместите эту строку:
$prod = new StdClass();
…внутри цикла:
while ( $row=sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) ) {
$prod = new StdClass(); // <----
$prod->mainInfo = $row['product'];
$prod->secondInfo = $row['qty'];
$arr[] = $prod;
}
В качестве альтернативы, вы можете использовать (object)
приведение и назначить новый объект за один раз, не прибегая к $prod
переменной:
while ( $row=sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) ) {
$arr[] = (object) [
"mainInfo" => $row['product'],
"secondInfo" => $row['qty']
];
}