Программирование

Как сформировать массив payments в PHP

Узнайте, как собрать массив payments с ключами new1, new2 и т.д. в PHP, избегая вложенных массивов, и исправьте ошибку array_push.

Как правильно сформировать ассоциативный массив payments в PHP, чтобы он имел следующую структуру:

php
array(3) {
  "seller" => object(SimpleXMLElement)#539 (1) {
    [0] => object(SimpleXMLElement)#546 (0) {}
  }
  "product_id" => int(2320617)
  "payments" => array(2) {
    "new1" => array(3) {
      "type" => string(7) "payment"
      "title" => string(9) "Тест1"
      "fields" => array(3) {
        "price" => string(5) "19999"
        "currency" => string(3) "RUB"
        "code" => string(4) "CODE"
      }
    }
    "new2" => array(3) {
      "type" => string(7) "payment"
      "title" => string(9) "Тест2"
      "fields" => array(3) {
        "price" => string(4) "9999"
        "currency" => string(3) "RUB"
        "code" => string(4) "CODE"
      }
    }
  }
}

А вот массив, который я получаю сейчас:

php
array(3) {
  "seller" => object(SimpleXMLElement)#539 (1) {
    [0] => object(SimpleXMLElement)#546 (0) {}
  }
  "product_id" => int(2320617)
  "payments" => array(16) {
    [0] => array(1) {
      "new1" => array(3) { ... }
    }
    [1] => array(1) {
      "new2" => array(3) { ... }
    }
    ...
  }
}

Т.е. у меня получается массив из 16 вложенных массивов, где каждый вложенный массив содержит один элемент с ключом newX. Это не соответствует требуемой структуре и приводит к ошибкам.

Мой текущий код:

php
$methods = /* массив со всеми методами */;
$ready = array();
for ($i = 0; $i < count($methods); $i++) {
    $arr = array('new'.$i+1 => [
        'type' => 'payment',
        'title' => strval($methods[$i]->name),
        'fields' => [
            "price" => strval($methods[$i]->currencies->currency->price),
            "currency" => strval($methods[$i]->currencies->currency->currency),
            "code" => strval($methods[$i]->code)
        ],
    ]);
    array_push($ready, $arr);
}

$payments = array(
    "seller" => $seller_name,
    "product_id" => $product_id,
    'payments' => $ready,
);

var_dump($payments);

Как исправить этот код, чтобы массив payments имел нужную структуру с ключами new1, new2 и т.д., а не массив из 16 вложенных массивов?

Краткий ответ
Чтобы получить массив вида

php
$payments = [
    'seller'     => $seller_name,
    'product_id' => $product_id,
    'payments'   => [
        'new1' => [/* … */],
        'new2' => [/* … */],
    ],
];

не обязательно использовать array_push.
Нужно просто пополнять ассоциативный массив $ready (или сразу $payments['payments']) ключами new1, new2 и т.д.

php
$ready = [];                     // ← ассоциативный массив
foreach ($methods as $idx => $method) {
    $ready['new' . ($idx + 1)] = [
        'type'   => 'payment',
        'title'  => (string)$method->name,
        'fields' => [
            'price'    => (string)$method->currencies->currency->price,
            'currency' => (string)$method->currencies->currency->currency,
            'code'     => (string)$method->code,
        ],
    ];
}

$payments = [
    'seller'     => $seller_name,
    'product_id' => $product_id,
    'payments'   => $ready,
];

Почему array_push ломает структуру

array_push($ready, $arr) добавляет значение $arr в конец массива $ready с числовым ключом (0, 1, 2 …).
В результате вы получаете

php
$ready = [
    0 => ['new1' => [...]],
    1 => ['new2' => [...]],
    // …
];

а не

php
$ready = [
    'new1' => [...],
    'new2' => [...],
];

К тому же в выражении 'new'.$i+1 оператор + имеет более высокую приоритетность, чем .
Таким образом 'new'.$i+1 сначала вычисляется как ('new' . $i) + 1, а не как 'new' . ($i + 1).
В итоге ключи могут получаться неверными (new01, new12 и т.д.).


Полный рабочий пример

php
<?php
$methods = /* массив со всеми методами */;
$seller_name = /* объект SimpleXMLElement */;
$product_id  = 2320617;

$ready = [];

foreach ($methods as $idx => $method) {
    // ключи new1, new2, …
    $key = 'new' . ($idx + 1);

    $ready[$key] = [
        'type'   => 'payment',
        'title'  => (string)$method->name,
        'fields' => [
            'price'    => (string)$method->currencies->currency->price,
            'currency' => (string)$method->currencies->currency->currency,
            'code'     => (string)$method->code,
        ],
    ];
}

$payments = [
    'seller'     => $seller_name,
    'product_id' => $product_id,
    'payments'   => $ready,
];

var_dump($payments);

Вывод будет точно таким, как показано в задаче:

array(3) {
  ["seller"]=>
  object(SimpleXMLElement)#... (1) {
    [0]=>
    object(SimpleXMLElement)#... (0) {}
  }
  ["product_id"]=>
  int(2320617)
  ["payments"]=>
  array(2) {
    ["new1"]=>
    array(3) { ... }
    ["new2"]=>
    array(3) { ... }
  }
}

Что можно улучшить

Что Как сделать
Чтение Использовать foreach вместо for ($i = 0; $i < count($methods); $i++).
Приведение типов В PHP 8 можно написать (string)$method->name вместо strval().
Переиспользуемость Выделить создание одного платежа в отдельную функцию: makePayment($method, $idx) и вызывать её в цикле.
Проверка данных Добавить проверки, что $method->currencies->currency существует, чтобы избежать ошибок.

Итого
Уберите array_push, замените его прямым присваиванием в ассоциативный массив, и убедитесь, что ключи формируются как 'new' . ($i + 1). Это создаст нужную структуру и избавит от лишних вложенных массивов.

Авторы
Проверено модерацией
Модерация