5

少し紹介を始めましょう。私はPHPでOOPを学んでいます。デザイン パターンについても調べましたが、さまざまな種類の概念をまだ完全には把握していません。私は数か月ごとに、自分のやり方が正しくないことに気づき、自分のスタイルを変えなければならない段階にいます. これはとてもイライラします。したがって、物事を行う正しい方法を一度だけ見つけたいと思います。次のトピックについて、Stackoverflow を完全に読み込もうとしました。

ORM
Data Mapper
シングルトン
グローバルは悪です
関連するすべて

ただし、いくつかのことについてはまだ明確ではありません。私は自分のコードを明確かつ簡潔な方法でここに投稿しています。人々が良い方法と悪い方法の両方を指摘できることを願っています。最後にすべての質問をリストします。

重複して閉じないでください。このトピックに関するほぼすべての質問を正直に検索しましたが、まだ明確にできていないいくつかのことを知りたい. 長くなってすみませんが、よく読めるように整理してみました!

データベース クラスの要点を投稿することから始めます。

データベース.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)呼び出されたクラスのオブジェクトを動的に生成するような静的メソッドを使用します。Late Static Binding を使用して、呼び出されたクラスの名前にアクセスし、 を使用し$stmt->fetchAll(PDO::FETCH_CLASS, $class_name)て、データベースからのデータを自動的にオブジェクトに変換してこれらのオブジェクトをインスタンス化します。

各静的メソッドで、DatabaseMySQL クラスのインスタンスをインスタンス化します。$table各静的メソッドでは、クラスの名前を取得してそれに追加することにより、SQL クエリで動的に使用される正しい静的名を設定しますs。したがって、私のクラスが だった場合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) このデザイン パターンを何と呼びますか? 依存性注入?ドメインモデル(それが何であれ)?データアクセスレイヤー?

  • 2) 現状では、この実装は適切に構造化されていると考えられますか?

  • 3) 良い場合、コードに欠けていることに注意する必要がある命名規則はありますか?

  • 4) 良いと思われる場合は、特に気に入った点を指摘していただけますか?

  • 5) 良いと思わない場合は、その理由を詳しく説明していただけますか?

  • 6) my オブジェクトのすべてのメソッドである my create,はupdate、静的にのみ呼び出され、実際にオブジェクトを返すmyとdelete同じクラスにある必要があります。彼らが2つの異なるクラスにいる必要がある場合、どうすればいいですか?find_by_idfind_all

  • 7) なぜ他の人は$load->('UserClass')関数やマッパーのような派手な言葉を使っているのに、私は一度もそれらを必要としたことがないのですか?

4

1 に答える 1

1

あなたが思いついた解決策は「Active Record」と呼ばれます。利点と欠点については、Martin Fowler の著書 Patterns of Enterprise Architecture や、インターネットで見つけられる多くの会話を読むことができます。

Fwiw、私の個人的な見解は、これは、主要なビジネス ロジックがデータベースの読み取りと書き込みであるデータベース駆動型アプリケーションを構築するための完全に優れた方法であるということです。より複雑なビジネス ロジックを構築する場合は、少し面倒になる傾向があります。

また、Stack Overflow は「このトピックについて話し合ってください」スタイルの質問ではなく、客観的に正しい回答がある回答を対象としています。したがって、質問1は当てはまりますが、他の質問はSOにはあまり適していません...

于 2012-08-27T21:05:59.690 に答える