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

Как найти значение в ассоциативном массиве PHP - методики

Эффективные способы извлечения значений из SimpleXMLElement по атрибутам. XPath, итерация и array_filter - лучшие практики.

Как найти значение в ассоциативном массиве?

Ниже приведен код моей xml-ки. Мне нужно получить значение 1090, опираясь на RUB.

[“product”]=>
object(SimpleXMLElement)#7567 (39) {
[“section_id”]=>
string(5) “22304”
[“pwyw”]=>
string(1) “0”
[“prices”]=>
object(SimpleXMLElement)#7168 (2) {
[“default”]=>
object(SimpleXMLElement)#5681 (1) {
[“price”]=>
array(6) {
[0]=>
object(SimpleXMLElement)#5688 (2) {
[“currency”]=>
string(3) “RUB”
[“price”]=>
string(4) “1090”
}
[1]=>
object(SimpleXMLElement)#5687 (2) {
[“currency”]=>
string(3) “USD”
[“price”]=>
string(5) “15.76”
}
}
}
}
}

Как это можно сделать?
Я пытался сделать вот так:

$price = $xml->product->prices->default->price->xpath(‘price[@currency=“RUB”]’);

Но это не работает. Подскажите, пожалуйста, как получить нужное мне значение?

Я понимаю, что “$xml->product->prices->default->price” - это массив. Так вот, хочется что-то на подобии как в JS воспользоваться filter(), но только надо на PHP. Ну или другое какое-то элегантное, красивое решение. Заранее спасибо каждому!

Чтобы найти значение в ассоциативном массиве в PHP, особенно при работе с SimpleXMLElement, есть несколько элегантных способов. Давайте разберем основные подходы на основе вашей структуры XML.

Содержание

XPath решение для фильтрации по валюте

Основная проблема в вашем коде - вы пытаетесь вызвать xpath() на массиве элементов, а не на объекте SimpleXMLElement. Правильный подход, честно говоря, довольно прост:

php
$price = $xml->xpath('//price[@currency="RUB"]');
if (isset($price[0])) {
    $rublePrice = (string)$price[0]->price;
    echo $rublePrice; // выведет "1090"
}

Как объясняется в официальной документации PHP, XPath запросы всегда выполняются на объекте SimpleXMLElement, который представляет корневой элемент или его дочерние элементы. Интересно, что многие новички в PHP допускают именно эту ошибку.

Почему ваш вариант не работал:

  • $xml->product->prices->default->price возвращает массив объектов SimpleXMLElement
  • Метод xpath() доступен только для объектов SimpleXMLElement, а не для массивов

Конвертация в массив и фильтрация

Если вы предпочитаете работать с массивами как в JavaScript, можно конвертировать SimpleXMLElement в массив. Этот подход, на мой взгляд, довольно удобен, если вы привыкли к традиционным PHP массивам:

php
// Конвертация всей структуры в массив
$pricesArray = json_decode(json_encode($xml), true);

// Фильтрация по валюте
$rublePrice = null;
foreach ($pricesArray['product']['prices']['default']['price'] as $price) {
    if ($price['@attributes']['currency'] === 'RUB') {
        $rublePrice = $price['price'];
        break;
    }
}

echo $rublePrice; // выведет "1090"

Этот метод полезен, если вам нужно работать с данными в традиционном формате PHP массивов. Хотя он и требует дополнительных шагов преобразования, иногда это стоит того.

Прямая итерация и поиск

Самый простой и понятный способ - прямая итерация по массиву цен. На самом деле, для многих разработчиков это самый интуитивный подход:

php
$rublePrice = null;
foreach ($xml->product->prices->default->price as $price) {
    if (isset($price['currency']) && (string)$price['currency'] === 'RUB') {
        $rublePrice = (string)$price->price;
        break;
    }
}

echo $rublePrice; // выведет "1090"

Этот подход интуитивно понятен и не требует специальных знаний XPath. К тому же, его легко читать и поддерживать, что немаловажно в долгосрочной перспективе.

Использование array_filter

Для более функционального стиля можно использовать array_filter. Если вы пришли в PHP из JavaScript или других языков с функциональными возможностями, этот способ покажется вам знакомым:

php
// Получаем массив цен
$prices = $xml->product->prices->default->price;

// Фильтруем по валюте
$rublePrices = array_filter($prices, function($price) {
    return isset($price['currency']) && (string)$price['currency'] === 'RUB';
});

// Получаем первое совпадение
$rublePrice = !empty($rublePrices) ? (string)reset($rublePrices)->price : null;

echo $rublePrice; // выведет "1090"

Этот метод похож на JavaScript filter() и будет знаком разработчикам с опытом в функциональном программировании. Хотя он и немного более сложен для новичков, опытные программисты оценят его лаконичность.

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

Вот полный пример, демонстрирующий все подходы. Я добавил немного комментариев, чтобы было понятнее:

php
<?php
// Создаем тестовую структуру (в вашем случае это будет loaded XML)
$xml = new SimpleXMLElement('<product>
    <section_id>22304</section_id>
    <pwyw>0</pwyw>
    <prices>
        <default>
            <price currency="RUB">1090</price>
            <price currency="USD">15.76</price>
        </default>
    </prices>
</product>');

// Способ 1: XPath
function getPriceByXPath(SimpleXMLElement $xml, $currency) {
    $result = $xml->xpath('//price[@currency="' . $currency . '"]');
    return isset($result[0]) ? (string)$result[0]->price : null;
}

// Способ 2: Прямая итерация
function getPriceByIteration(SimpleXMLElement $xml, $currency) {
    foreach ($xml->product->prices->default->price as $price) {
        if (isset($price['currency']) && (string)$price['currency'] === $currency) {
            return (string)$price->price;
        }
    }
    return null;
}

// Способ 3: array_filter
function getPriceByFilter(SimpleXMLElement $xml, $currency) {
    $prices = $xml->product->prices->default->price;
    $filtered = array_filter($prices, function($price) use ($currency) {
        return isset($price['currency']) && (string)$price['currency'] === $currency;
    });
    return !empty($filtered) ? (string)reset($filtered)->price : null;
}

// Использование всех методов
$rubPriceXPath = getPriceByXPath($xml, 'RUB');
$rubPriceIteration = getPriceByIteration($xml, 'RUB');
$rubPriceFilter = getPriceByFilter($xml, 'RUB');

echo "XPath: $rubPriceXPath\n";         // 1090
echo "Iteration: $rubPriceIteration\n"; // 1090
echo "Filter: $rubPriceFilter\n";       // 1090
?>

Рекомендации по выбору метода

Выбирайте XPath, когда:

  • Вам нужно сложное условие фильтрации
  • Работа с большими XML документами
  • Производительность критически важна

Выбирайте итерацию, когда:

  • Код должен быть максимально понятным
  • Простые условия фильтрации
  • Вы предпочитаете традиционный подход PHP

Выбирайте array_filter, когда:

  • Вам нравится функциональный стиль программирования
  • Нужно применить дополнительные преобразования к результатам
  • Код должен быть лаконичным

Лично я чаще всего использую XPath для сложных запросов, а итерацию - для простых случаев. array_filter применяю реже, в основном когда нужно цепочку операций выполнить. Как показано в примерах на StackOverflow, все эти методы широко используются в практике разработки и выбор зависит от конкретных задач и предпочтений разработчика.

Источники

  1. PHP SimpleXMLElement::xpath - Официальная документация
  2. PHP filter XML by attribute - Stack Overflow
  3. SimpleXML Attributes to Array - Stack Overflow
  4. PHP XPath Function - W3Schools
  5. Searching and filtering with XPath - Hacking with PHP

Заключение

  • Для фильтрации SimpleXMLElement по атрибутам используйте XPath с синтаксисом //price[@currency="RUB"]
  • Основная ошибка в вашем коде - вызов xpath() на массиве вместо объекта SimpleXMLElement
  • Три основных подхода: XPath, прямая итерация и array_filter - каждый имеет свои преимущества
  • XPath наиболее эффективен для сложных запросов, а итерация и array_filter более понятны для простых случаев
  • Все методы успешно решают задачу получения значения “1090” для валюты RUB из вашей структуры XML
Авторы
Проверено модерацией
Модерация