gpt4 book ai didi

php - 与 PDO::FETCH_CLASS 相反

转载 作者:行者123 更新时间:2023-11-29 10:41:28 26 4
gpt4 key购买 nike

因此,我使用 PDO::FETCH_CLASS 来创建一个新对象,并使用数据库中同名列中的值填充属性,如下所示:

$db = Connection::get();
$sql = $db->prepare("SELECT * FROM table WHERE id = :id");
$sql->bindParam(":id", "1");
$sql->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'table');
$sql->execute();
$newobj = $sql->fetch();

是否有相反的方法将对象的属性插入到表中相应的列中,以节省键入整个 bindParam() 负载和较长的 SQL 查询?

非常感谢

最佳答案

这是一件有趣的事情

  • 需要注意的是,这将获取类中的所有 public 属性,并尝试将它们用作查询的一部分。如果确实需要,您可以对它们进行更多过滤。

我们将使用所谓的反射。

这是一把双刃剑。

一方面,我们可以将其放入基类中,并使用所有对象扩展它,这对它们来说效果很好。如果稍后您向表中添加字段,同样您无需更改任何内容,它就可以正常工作。

另一方面,处理这个问题需要花费少量的时间,而不是把它写成字符串。其中一些问题可以通过缓存 protected 静态属性内的查询以及缓存属性本身(但不是值)来解决

我将从创建一个抽象类开始。这是解决这个问题的一种非常灵活的方法,并且它可以被重用 - 注意:我只测试了 Insert 方法,所以如果其他部分有任何错误,请原谅我。

  abstract class BaseObject
{

public $id;
protected static $_DB;

public function getDB(\PDO $db ){
if( !self::$_DB ){
//@todo: connect to Database
}
return self::$_DB;
}

public function getId(){ return $this->id; }

public function setId( $id ){ $this->id = $id }

//returns the records id
public function save(){
//if there is no ID then we know it didn't come from the DB
if( $this->id )
return $this->update();
else
return $this->insert();
}

// query format = 'INSERT INTO table (id, ... )VALUES(:id, ... )'
public function insert(){
$this->validate();

$db = $this->getDB(); //localize

$R = new \ReflectionObject( $this );
$props = (array)$R->getProperties()[0];

$names = array_keys( $props );

$sql = 'INSERT INTO '.$this->getTable().' ('.implode(',', $names).' )VALUES( :'.implode(', :', $names).' )';
$params = array_combine(
array_map(function($item){
return ':'.$item;
}, $names),
$props
);

$stmt = $db ->prepare( $sql );
$stmt->execute( $params );

$this->id = $db->lastInsertId(); //don't forget to update the id
return $this->id;
}

// query format = 'UPDATE table SET prop=:prop, ... WHERE id=:id'
public function Update(){
$this->validate();

$db = $this->getDB(); //localize

$R = new \ReflectionObject( $this );
$props = (array)$R->getProperties()[0];
$names = array_keys( $props );

$sql = 'UPATE '.$this->getTable().' SET ';
$set = [];
$params = [];
foreach( $props as $name=>$value ){
$params[':'.$name] = $value;

if( $name == 'id' ) continue;
$set[] = "$name = :$name";
}

$sql .= implode(', ', $set).' WHERE id=:id'


$stmt = $db->prepare( $sql );
$stmt->execute( $params );

return $this->_id;
}

abstract public function getTable();

abstract public function vallidate();

}

然后在具体类中,您只需要实现抽象方法,并添加特定于它们的其他属性

  class Dude extends BaseObject
{
public $name;

public function getName(){ return $this->name ; }

public function setName( $name ){ $this->name = $name }

public function getTable(){
return 'dudes';
}

public function validate(){
if( empty( $this->name ) ) throw new \Exception( "Name cannot be empty" );

//...etc.
}
}

我碰巧想到您应该注意的一件事,当通过 PDO 结果加载类时,不会调用该类的构造函数。我以这种方式加载类已经有一段时间了,可能有一种方法可以强制它调用构造函数,或者我可能只是记忆错误。但这是值得一提的。

我提到这一点的原因是抽象类需要一个 PDO 实例,所以我添加了 getDB() 方法。这只是一个关于如何缓存所有类的数据库连接的简短示例,(我懒得做实际的连接部分,抱歉)

就我个人而言,我使用所谓的 Singleton 来满足我的数据库需求,因此我只需调用类似这样的东西 self::$_DB = DB::getInstance();就在那里,但那是另一天的故事了。

我还建议添加一个 delete 方法,这样您就可以获得所有程序员爱好者一直在谈论的完整 CRUD 体验。

我能想到的另一个主要改进是您可以将其中一些内容存储在静态属性中,基本上在第一次运行后缓存它。这将节省一些对类的多次重新处理(内省(introspection))的时间。

不过这有点棘手,你会想要进一步分解。我可以给你的一个提示是,确保在基类中使用 static::$Var 而不是 self::$Var,这样你就可以使用所谓的 >后期静态绑定(bind)。这基本上是棘手的部分,因为您可能会拥有包含完全不同内容的后代类。我不确定这是否是正确的术语,但这是一种范围解析问题。

但我会把最后的事情留给你。这个例子应该为您指出正确的路径(或者至少是我知道可行的路径),并为您提供一些关于可能性的想法。

最后一件事是使用这样的字符串访问属性或调用方法是完全可以的(当然假设它们存在)

foreach( $props as $name=>$value ){
//for this we will say $name = 'id'
$method = "get".ucFirst( $name ); // 'getId'
$a = $this->$method(); // calls $this->getId()
$a = $this->$name; //access property $this->id;
}

我只是想把它放在那里,为您提供另一种方式来访问您可能认为有用的数据。

关于php - 与 PDO::FETCH_CLASS 相反,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45396094/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com