2012-08-27 3 views
5

조금 소개로 시작하겠습니다. PHP에서 OOP를 배우는 중입니다. 필자는 디자인 패턴을 연구했지만 다른 유형의 개념을 아직 완전히 파악하지 못했습니다. 저는 몇 달에 한 번씩 올바른 방식으로 일을하지 않고 제 스타일을 바꾸어야한다는 것을 알게되었습니다. 매우 실망 스럽습니다. 그러므로 나는 한 번에 모든 일을하는 올바른 방법을 찾고 싶습니다. 나는 완전히 다음과 같은 항목에 대한 유래에 읽을 것을 시도했다 :PHP의 OOP 프로그래밍에서 클래스를 설정하는 올바른 방법은 무엇입니까?

ORM
데이터 매퍼
싱글
을 전역는

관련된 모든 그러나 나는 아직도 몇 가지를 분명히 아니다 악. 여기에 명확하고 간결한 방식으로 코드를 게시하고 사람들이 모두 좋은 사례와 나쁜 사례를 지적 할 수 있기를 바랍니다. 마지막에 모든 질문을 나열 할 것입니다.

필자는 복제본으로 닫지 마십시오. 주제에 관한 거의 모든 질문을 솔직히 조사했지만, 아직 명확히 할 수없는 몇 가지 사실을 알고 싶습니다. 미안하지만 너무 길지만 잘 읽을 수 있도록 정리하려고했습니다!

데이터베이스 클래스의 필수 사항을 게시하여 시작하겠습니다.

Database.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 Bindings를 사용하여 호출 된 클래스의 이름에 액세스합니다. $stmt->fetchAll(PDO::FETCH_CLASS, $class_name)을 사용하여 이러한 객체를 데이터베이스의 데이터로 인스턴스화하고 객체로 자동 변환합니다.

각 정적 메서드에서 DatabaseMySQL 클래스의 인스턴스를 인스턴스화합니다. 각 정적 메서드에서 클래스 이름을 가져 와서 s을 추가하여 SQL 쿼리에서 꼼꼼하게 $table이라는 정적 이름을 사용하도록 설정했습니다. 그래서 내 수업이 User이라면 테이블 이름은 users이됩니다.

제 생성자에서 객체가 생성 될 때 객체의 속성으로 일부 변수를 삽입하는 데 사용할 수있는 선택적 배열을 배치했습니다. 이렇게하면 모든 것이 동적으로 완료되어 프로젝트의 마지막 단계가됩니다. 내 상속 수업.

User.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::find_by_id(1); 
echo $user->username; // prints users name 

:

  • 1)도 하나 전혀) .DATA 매퍼 경우 (이 디자인 패턴라고 부르는 이름은? 의존성 주사? 도메인 모델 (그게 뭐든간에)? 데이터 액세스 레이어?

  • 2)이 구현은 현재 잘 구조화 된 것으로 간주됩니까?

  • 3) 좋으면, 내 코드에서 빠뜨린 이름 지정 규칙이 있습니까?

  • 4) 좋은 것으로 생각되면 특히 좋아하는 부분을 지적 해 주시면 분명히 유지할 부분을 알 수 있습니까?

  • 5) 왜 그렇게 생각하는지 모르겠 으면 자세한 설명이 필요하십니까?

  • 6) 해야하는 내 create, update, 내 find_by_id, 정적으로 불리는 find_all와 같은 클래스에있을 실제로 개체를 반환 내 개체의 모든 메소드입니다 delete. 그들이 두 개의 다른 클래스에 있어야한다면 어떻게해야합니까?

  • 7) $load->('UserClass')을 사용하는 다른 모든 사람들이 왜 매퍼와 같은 기능과 멋진 단어를 사용하지만 아직 한 번 필요하지 않은 이유는 무엇입니까?

+4

이것은 더 맞는 여기에 : http://codereview.stackexchange.com/ –

+1

@IliaRostovtsev 내가 그걸 알았지 만 고마워,하지만 난 여전히 전문가의 답변을 원하고 그들이 주로 여기 있다고 생각합니다! –

+3

No.주제를 읽지 마라. (나는 SO를 첫 번째 참조로 사용하는 것을 꺼린다.) 경험을 쌓고 두려워하지 마십시오.이 질문은 좋은 출발입니다. 흑백이 없음을 알아라. 문맥을 알지 못하지만 전역은 반드시 악의가있는 것은 아니며 오용되면 무서운 것입니다. ORM과 Singleton에 대해서도 마찬가지입니다. 그리고 모든 것이 --- 때로는 우수 사례이지만 항상 최고는 아닙니다. – skytreader

답변

1

해결 방법은 "Active Record"입니다. 이점과 단점을 위해 Martin Fowler의 책인 Enterprise Architecture의 패턴과 인터넷에서 볼 수있는 많은 대화를 읽을 수 있습니다.

Fwiw, 내 개인적인 관점은 이것이 기본 비즈니스 로직이 데이터베이스에 읽고 쓰는 데이터베이스 기반 응용 프로그램을 구축하는 완벽한 방법이라는 것입니다. 더 복잡한 비즈니스 로직을 구축 할 때 약간 부담이되는 경향이 있습니다.

또한 스택 오버플로는 "이 주제에 대해 토론하십시오"스타일 질문이 아닙니다. 객관적으로 참된 대답이있는 대답입니다. 그럼, 귀하의 질문에 맞는 1,하지만 다른 사람은 정말 적합하지 않습니다 ...

+0

네빌에게 시간을내어 주셔서 감사합니다. 제 질문이 토론 주제 였다고 생각하지 않았습니다. 질문 3과 질문 6은 어떻게됩니까? –

+0

@InGodITrust 어쩌면 당신은 하나님 = p. 3 ~ 6 번 답변 : 명명 규칙 및 네임 스페이스에 대한 내용은 [PSR-0] (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)을 참조하십시오. , 바로 지금 표준입니다. 당신의 방법에 관해서는, 그들 모두를 같은 반에 두는 것이 좋습니다. ORM에서 DBAL을 분리하는 것도 고려해야합니다. 조회 연결 부분과 엔티티/관계 부분에서 연결 부분을 분리해야합니다. 이것은 모두 학습에 좋으며, 나는 그것을 또한했습니다. 하지만 실제 프로젝트의 경우 Doctrine2 나 Symfony2와 같이 잘 테스트 된 라이브러리를 사용해야합니다. – ChocoDeveloper

+0

@ChocoDeveloper 나는 그에게 묻고 아직도 답장을 기다리고있다. 팁, 당신이 준 훌륭한 링크 주셔서 감사합니다! –

관련 문제