如何获取第一行作为类的对象? (PDO)

时间:2016-11-30 21:35:26

标签: php pdo

我从phpdelusions借用了以下包装类:

class DB
{
    protected static $instance = null;

    public static function instance() {
        if (self::$instance === null) {
            $opt  = array(
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_CLASS,
                PDO::ATTR_EMULATE_PREPARES   => FALSE,
            );
            $dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
            self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
        }
        return self::$instance;
    }

    public static function __callStatic($method, $args) {
        return call_user_func_array(array(self::instance(), $method), $args);
    }

    public static function run($sql, $args = []) {
        $stmt = self::instance()->prepare($sql);
        $stmt->execute($args);
        return $stmt;
    }
}

我还设置了users表格idnamepassword。现在,我正在尝试将表中的第一个行作为类User对象(假设某个地方有一个require_once 'User.php',加载模型类):

$stmt = DB::run('SELECT * FROM users LIMIT 1');
$user = $stmt->fetchAll(PDO::FETCH_CLASS, 'User'); // Array ( [0] => User Object ( ... ) )

它有效,但

  1. fetchAll总是返回一个数组,如果上面的查询以某种方式被破坏,结果可能是User个可变对象,而目标是始终获得一个,即第一个对象,即使查询返回多行。
  2. 此外,(2)尽管PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_CLASS instance()方法中的DB将默认提取样式设置为CLASS,但我始终必须在{{1}中指定PDO::FETCH_CLASS我认为这是多余的。
  3. 最后,要真正获得第一行,我总是需要检查fetchAll,因为您永远不知道$first = (is_array($user)) ? $user[0] : null;是否为空。只获取第一个对象并获得合法的行($user对象)或仅为null将更容易。如果您的目标是获得一个对象,那么返回阵列是没有意义的吗?
  4. 所以我尝试将User改为fetchAll,但有多种变体,这就是我所得到的:

    fetch

    问题

    是否可以仅使用$user = $stmt->fetch('User'); // # 1, FETCH_MODE is already CLASS, but no... // Warning: PDOStatement::fetch() expects parameter 1 to be integer, string given $user = $stmt->fetch(PDO::FETCH_CLASS, 'User'); // # 2 // Warning: PDOStatement::fetch() expects parameter 2 to be integer, string given $user = $stmt->fetch(); // #3 // Uncaught PDOException: SQLSTATE[HY000]: General error: No fetch class specified // so how do you specify it then with fetch() ??? 将第一行作为给定类的对象获取?或者我别无选择,只能写fetch,然后运行$stmt->setFetchMode(PDO::FETCH_CLASS, 'User');

2 个答案:

答案 0 :(得分:2)

由于您只想要一个对象,我完全理解您不想使用fetchAll()的原因。但既然你想要一个,为什么不使用fetchObject()

因为它完全能够在while循环中使用。它就像对象的fetch()一样。

  

返回所需类的实例,其属性名称对应于列名称,如果失败则返回FALSE。

public mixed PDOStatement::fetchObject ([ string $class_name = "stdClass" [, array $ctor_args ]] )

示例:

class User{
  protected $data = [];

  public function __get(string $key){
    return $this->data[$key];
  }

  public function __set(string $key, $value){
    $this->data[$key] = $value;
  }

  public function __construct($a, $b, $c){
    echo $a, $b, $c;
    print_r($this->data);
  }
}

$stmt = DB::run('SELECT id, name FROM users LIMIT 1');

if($user = $stmt->fetchObject('User', [1, 2, 3])){
  echo $user->id;
}

答案 1 :(得分:2)

如我所见,您正在使用我的PDO包装器。所以你只需点击一下右边的答案,因为有一篇姊妹文章Fetching objects with PDO:)

因此,要使用fetch(),您需要额外的函数调用

$stmt->setFetchMode(PDO::FETCH_CLASS, 'User');
$user = $stmt->fetch();

但是,正如在另一个答案中正确地说的那样,fetchObject()在任何一种情况下都更好:

$user = DB::run('SELECT * FROM users LIMIT 1')->fetchObject('User');