PDO: Опция извлечения класса для отправки полей конструктору в виде массива


Эй, парни (и девушки?) Мне интересно, можно ли элегантно сопоставить результаты запроса PDO с членом массива в классе, а не использовать их в качестве общедоступных свойств этого объекта.

Скажем, у меня есть (сокращенное) следующее:

class DBObject {

    protected
        $record = array();

    function __construct(array $record) {
        if(!empty($record)) {
            $this->loadRecord($record);
        }
    }
}

В идеале я хочу вызвать конструктор с массивом значений, переданных из базы данных, а не использовать __set или любые другие странные методы. Так что использование существующего API PDO было бы здорово.

Мой грубый get_all функция на данный момент зашла так далеко:

static function get_all() {
    $class = get_called_class();
    $results = DB::factory()->query('SELECT * FROM ' . $class . ' ORDER BY ID');
    $results->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, $class);
    return $results;
}

NB: Я запускаю PHP 5.3 и MySQL через PDO и уже знаю, что эта проблема разрешима с помощью __set, но я явно хочу избежать ее использования в пользу чего-то более производительного.

Author: Will Morgan, 2012-02-27

3 answers

Удален предыдущий код


Верно, разве ты не можешь сделать что-то подобное:
class DBObject {

    protected $record = array();

    function __construct($record = null) {
        if(null === $record){
            $obj_vars = get_object_vars($this);
            $cls_vars = get_class_vars(get_class($this));
            $this->$record = array_diff_key($obj_vars, $cls_vars);
        }else{
            $this->record = $record;
        }
    }
}

Проблема с этим, однако, заключается в том, что значения по-прежнему доступны в качестве общедоступных элементов. Но то, что он будет делать, - это сравнивать "предопределенные" (классовые) члены с фактическими (объектными) членами.

Поскольку PDO создаст новые элементы в объекте, вы можете использовать array_diff_key для получения "новых" элементов.

Да, это все равно не передаст их через ваш конструктор.

 1
Author: Daan Timmer, 2012-02-29 23:14:31

Вам не нужно передавать аргументы конструктору, чтобы создать класс с закрытыми членами с помощью PDO::FETCH_CLASS. Вы можете сделать что-то вроде этого:

<?php
class Songs
{  

    private $artist;
    private $title;

    public function __construct()
    {  
    }

    public function get_artist()
    {
    return $this->artist;
    }

    public function get_title() 
    {
    return $this->title;
    }

    private function set_artist($artist) 
    {
    $this->artist = $artist;
    }

    private function set_title($title) 
    {
    $this->title = $title;
    }
}

На самом деле я делаю это на демо-сайте, который я создал. Это отлично работает с PDO::FETCH_CLASS. По умолчанию FETCH_CLASS создает объекты, заполняя поля ПЕРЕД конструктором. Думайте об этом как об обход конструктора. И он будет делать это с частными участниками.

Если вы предпочитаете передавать аргументы в конструктор вы можете выполнить свой запрос следующим образом:

$obj = $statement->fetchALL(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'Songs', $params);

В этом случае ваш конструктор будет выглядеть так:

public function __construct($params)
{
    $this->artist = $params[0]['artist'];
    $this->title= $params[0]['title'];
}
 3
Author: Neil Girardi, 2012-07-04 02:56:07

Как насчет использования метода magic __set():

<?php
class MyClass
{
    protected $record = array();

    function __set($name, $value) {
        $this->record[$name] = $value;
    }
}

$pdo = new PDO("mysql:host=localhost;dbname=db", 'user', 'password');
$results = $pdo->query('SELECT * FROM table');
$results->setFetchMode(PDO::FETCH_CLASS, 'MyClass');

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

 0
Author: Janci, 2012-02-28 12:53:23