php - 在 PHP 的 OOP 编程中设置我的类的正确方法是什么?

标签 php mysql database oop design-patterns

很难说出这里问的是什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或言辞激烈,无法以目前的形式合理回答。如需帮助澄清此问题以便可以重新打开,visit the help center .




9年前关闭。




让我先做一个简单的介绍。我正在学习 PHP 中的 OOP。我也研究过设计模式,但还没有完全掌握不同类型的概念。我正处于每隔几个月就会意识到我没有以正确的方式做事并且必须改变我的风格的阶段。 这太令人沮丧了。 因此,我想一劳永逸地找出正确的做事方式。我试图完全阅读 Stackoverflow 上关于以下主题的内容:

ORM
数据映射器
单例
全局是邪恶的
一切相关

但是,我仍然不清楚一些事情。我在这里以清晰简洁的方式发布我的代码,希望人们能指出两者 好的做法和坏的做法。我会在最后列出我所有的问题。

请不要关闭重复,我已经诚实地搜索了几乎所有关于该主题的问题,但我仍然想知道一些我无法澄清的事情。对不起,它太长了,但我试图组织它,所以它应该读得好!

我将首先发布我的数据库类(class)的要点。

数据库.php

<?php 


class DatabaseMySQL{

    private static $dbh;

    public function __construct(){
        $this->open_connection();
    }

    public function open_connection(){
        if(!self::$dbh){
            return (self::$dbh = new PDO(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER,DB_PASSWORD)) ? true : false;
        }
        return true;
    }

    public function query($sql, $params=array()){
        $this->last_query = $sql;
        $stmt = self::$dbh->prepare($sql);
        $result = $stmt->execute($params);  
        return $result ? $stmt : $stmt->errorInfo();
    }

    public function fetch_all($results, $class_name=''){
        return $results->fetchAll(PDO::FETCH_CLASS, $class_name);
    }

}

?>

这是我的数据库类文件。此类允许我创建尽可能多的此类实例,并且它将重用已实例化的 PDO 对象存储为类的静态属性。它还使用 PDO 从结果集中获取数据,以将数据作为指定类的对象。

我的下一个文件是我的所有其他类继承的类。我称之为 MainModel。我不知道这是否符合惯例。

MainModel.php
<?php



abstract class MainModel{

    protected static $table;

    public function __construct($array=array()){
        $this->assign_known_properties($array);
    }

    public function assign_known_properties($array){
        foreach($array as $key=>$value){
            $this->$key = $value;
        }
    }

    public static function find_by_id($id){
        $db = new DatabaseMySQL();
        self::intialise_table_name();
        $id = (int) $id;
        $sql = "SELECT * FROM ".static::$table." ";
        $sql .= "WHERE id = {$id} ";    
        $result = self::find_by_sql($sql);      
        return array_shift($result);
    }

    public static function find_all(){
        $db = new DatabaseMySQL();
        self::intialise_table_name();
        $sql = "SELECT * FROM ".self::$table." ";
        return self::find_by_sql($sql);
    }

    public static function fetch_as_objects($results){
        $db = new DatabaseMySQL();
        $called_class = get_called_class();
        $results = $db->fetch_all($results, $called_class);
        return $results;
    }

    public static function find_by_sql($sql){
        $db = new DatabaseMySQL();
        $results = $db->query($sql);
        return $results ? self::fetch_as_objects($results) : false; 
    }

    public static function intialise_table_name(){
        $called_class = get_called_class();
        static::$table = strtolower($called_class).'s';
    }

    public function get_table_fields(){
        self::intialise_table_name();
        $sql = "SHOW FIELDS FROM ".static::$table." ";
        return self::find_by_sql($sql);
    }

    public function set_table_details(){
        $fields = $this->get_table_fields();
        $total = count($fields);
        $array = array();
        foreach($fields as $object){
            $array [] = $object->Field;
        }
        $this->table_details = array('objects'=>$fields,'array'=>$array,'total'=>$total);
        $this->set_placeholders_for_new_record();
        $this->set_properties_as_array();
        $this->set_properties_as_array(true);
    }

    public function set_properties_as_array($assoc=false){
        $array = array();
        if (!$assoc){
            foreach($this->table_details['array'] as $field){
                if(isset($this->$field)){
                    $array [] = $this->$field;
                }else{
                    $array [] = NULL;
                }
            }
            $this->table_details['values'] = $array;
        }else{
            foreach($this->table_details['array'] as $field){
                if(isset($this->$field)){
                    $array[$field] = $this->$field;
                }else{
                    $array [$field] = NULL;
                }
            }
            $this->table_details['assoc_values'] = $array;
        }
    }

    public function set_placeholders_for_new_record(){
        $string = '';
        for($i=0; $i<$this->table_details['total']; $i++){
            $string .= '? ';
            if(($i+1) != $this->table_details['total'] ){
                $string .= ", ";
            }
        }
        $this->table_details['placeholders'] = $string;
    }

    public function create(){
        $db = new DatabaseMySQL();
        $this->set_table_details();
        $sql = "INSERT INTO ".static::$table." ";
        $sql .= " VALUES({$this->table_details['placeholders']}) ";
        $result = $db->query($sql, $this->table_details['values']);

        // If array is returned then there was an error.
        return is_array($result) ? $result : $db->insert_id();
    }

    public function update(){
        $db = new DatabaseMySQL();
        $this->set_table_details();
        $sql = "UPDATE ".static::$table." ";
        $sql .= " SET ";
            $count = 1;
            foreach($this->table_details['array'] as $field){
                $sql .= "{$field} = :{$field} ";
                if($count < $this->table_details['total']){
                    $sql .= ", ";
                }
                $count++;
            }

        $sql .= " WHERE id = {$this->id} ";
        $sql .= " LIMIT 1 ";
        $result = $db->query($sql, $this->table_details['assoc_values']);
        return $result;
    }

    public function save(){
        return isset($this->id) ? $this->update() : $this->create();
    }
}


?>

总结一下这个文件。我使用静态方法,如 find_by_id($int)动态生成被调用类的对象。我使用后期静态绑定(bind)来访问被调用类的名称,我使用 $stmt->fetchAll(PDO::FETCH_CLASS, $class_name)用数据库中的数据自动转换为对象来实例化这些对象。

在每个静态方法中,我实例化了 DatabaseMySQL 类的一个实例。在每个静态方法中,我设置了正确的静态 $table通过获取类的名称并附加 s 动态地在 SQL 查询中使用的名称到它。所以如果我的类(class)是 User ,这将使表名 users .

在我的构造函数中,我放置了一个可选数组,该数组可用于在创建对象时插入一些变量作为对象的属性。这样一切都是动态完成的,这让我进入了项目的最后阶段。我的继承类。

用户.php
class User extends MainModel{

}

Question.php
class Question extends MainModel{

}

我现在做的很简单。我可以说:
$user = new User(array('username'=>'John Doe'));
echo $user->username; // prints *John Doe*
$user->save(); // saves (or updates) the user into the database.

我可以通过静态调用 User 来检索用户。
$user = User::find_by_id(1);
echo $user->username; // prints users name

所以现在我的问题:
  • 1) 你会给这个设计模式起什么名字(如果它甚至是一个)。Data Mapper?依赖注入(inject)?领域模型(不管那是什么)?数据访问层?
  • 2)就目前而言,这种实现是否结构良好?
  • 3)如果它很好,我的代码中是否缺少我应该注意的命名约定?
  • 4)如果觉得不错,你介意指出你特别喜欢的东西,这样我就知道肯定要保留哪一部分吗?
  • 5)如果你认为它不好,你愿意详细解释为什么会这样吗?
  • 6) 应该我的 create , update , delete我的对象的所有方法都与我的 find_by_id 在同一个类中, find_all仅静态调用并实际返回对象。如果他们应该在两个不同的类(class),我该怎么做?
  • 7) 为什么其他人都在使用 $load->('UserClass')函数和像映射器这样的花哨的词,我还没有用过一次吗?
  • 最佳答案

    您提出的解决方案称为“Active Record”;对于优点和缺点,您可以阅读 Martin Fowler 的《企业架构模式》一书,以及您可以在 Internet 上找到的许多对话。

    Fwiw,我个人的观点是,这是构建数据库驱动应用程序的完美方式,其中主要业务逻辑是读取和写入数据库;在构建更复杂的业务逻辑时,它往往会变得有点麻烦。

    此外,Stack Overflow 不是针对“请讨论这个话题”风格的问题——而是针对有客观真实答案的答案。所以,您的问题 1 适合,但其他问题并不适合 SO...

    关于php - 在 PHP 的 OOP 编程中设置我的类的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12148211/

    相关文章:

    php - 关闭 MySQL 连接 (PHP)

    php - 如何使用单个查询从两个表中选择数据

    php - 插入数据时,Mysql 会自动创建一个额外的行

    javascript - 从内存(而不是数据库)提供后端数据

    html - 避免 TinyMCE 保存 <html> 标签

    PHP - mysql_numrows() 期望参数 1 是资源, bool 值给出

    mysql - 使用子查询作为字段列

    MySQL 重复 'ID' = 0 并且无法将 AUTO_INCREMENT 放在

    java - spring-boot JPA 不自动生成表

    php - MySQL SELECT 条件基于最后一行和日期间隔