Arris
@Arris
Сапиенсы учатся, играя.

PDO::FETCH_FUNC или как получить имена параметров, переданных в замыкание?

Предположим, есть код:

$query = "SELECT * FROM users_ban ORDER BY expiration_date DESC ";
$ln = [];

$sth = $pdo->query($query);
while ($row = $sth->fetch()) {
  $row['ipv4'] = long2ip($row['ipv4_long']);
  $ln[] = $row;
}


Хочется его переделать во что-то подобное:

...
$sth = $pdo->query($query);
$ln = $sth->fetchAll(PDO::FETCH_FUNC, function($row) { 
  $row['ipv4'] = long2ip($row['ipv4_long']);
  return $row;
} );


К сожалению, PDOStatement::fetchAll(PDO::FETCH_FUNC, $closure)` передает параметры списком, а не массивом.

Когда параметра два - это еще туда-сюда, а когда их неизвестное количество с неизвестными именами (то есть мы хотим решить задачу в общем виде)?

Как получить внутри замыкания имена параметров?

Казалось бы, простой вопрос:

func_get_args() ?

Если бы. func_get_args() возвращает только значения аргументов, но не имена.
array(5) {
  [0]=>   string(3) "130"
  [1]=>   string(10) "2177727624"
  [2]=>   string(19) "2020-10-28 00:50:17"
  [3]=>   string(1) "0"
  [4]=>   string(0) ""
}


Вроде бы существует плоходокументированный `ReflectionFunction`, но его конструктор принимает имя функции или замыкание, то есть вызвать его из замыкания... я не понял как.

Кроме того, попытка работать с Reflection изнутри замыкания приводит к непонятному
SQLSTATE[HY000]: General error: could not call user-supplied function


И что делать?

Как передать в коллбэк для PDO::FETCH_FUNC параметры асс.массивом ИЛИ как из коллбэка получить их ассоциативным массивом?

P.S. Идею вызывать fetchAll() с параметром PDO::FETCH_CLASS я отбрасываю в виду очевидной сложности. Класс недостаточно создать, нужно еще где-то в классе (то есть отдельно) описать правила преобразования полей, потом вернуть значения из класса - а магический метод __toArray() появится только в PHP8. В общем, из пушки по воробьям, в общем случае.
  • Вопрос задан
  • 211 просмотров
Решения вопроса 2
Arris
@Arris Автор вопроса
Сапиенсы учатся, играя.
Решение найдено и сделано на основе ответа profesor08 :

$sth = $dbh->query("SELECT * FROM users_ban ORDER BY expiration_date DESC ");    

$users = $sth->fetchAll(PDO::FETCH_CLASS, stdClass::class);
        
$ln = array_map(function($row) {
     $n = clone $row;
     $n->ipv4 = long2ip($n->ipv4_long);
     return (array)$n;
}, $users);
Ответ написан
profesor08
@profesor08 Куратор тега PHP
Создай класс для результата запроса, но наверняка он у тебя уже есть, ведь так удобнее, есть подсказки в ide, синтаксический анализ, подсветка ошибок и куча прочих ништяков помогающих не обосраться на какой-то фигне. А если, нет то создай.

class Book {
  public $id;
  public $title;
  public $author;
}

// тут массив инстансов класса Book
$books = $sth->fetchAll(PDO::FETCH_CLASS, Book::class);

// далее array_map и преобразовывай что хочешь и как хочешь.
$newBooks = array_map(function($book) {
  $newBook = clone $book;
  $newBook=>title = "New Title";
  return $newBook;
}, $books);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
FanatPHP
@FanatPHP
Чебуратор тега РНР
Насколько я знаю - напрямую нельзя.
Так что только паллиативы, например добавить к запросу , inet_ntoa(ipv4_long) as ipv4

В принципе, никто особо с этими режимими не парится - у всех все равно ОРМы, в которых такие преобразования - штатная функциональность
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы