복붙노트

[SQL] 클래스에서 전역 변수를 사용하여

SQL

클래스에서 전역 변수를 사용하여

나는 매김 클래스를 생성하고 클래스 외부에서 변수를 사용하는 것을 시도하고있다.

그러나 그것은 나에게 치명적인 오류 "가 아닌 객체의 멤버 함수 쿼리 ()를 호출"을주고있다.

이 인덱스 파일입니다 :

$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");

$pagination = new pagi();
$records = $pagination->get_records("SELECT * FROM `table`");

그리고 이것은 pagi.php 파일은 다음과 같습니다

class pagi {

    public function get_records($q) {
        $x = $db->query($q);
        return $db->fetch($x);
    }

}

이 클래스 내부 새로 만들지 않고, 클래스의 내부 클래스의 밖으로 측면에서이 변수를 사용할 수 있습니까?

해결법

  1. ==============================

    1.이 문제를 해결하는 올바른 방법은 다른 클래스 (의존성 주입)에 데이터베이스 객체를 삽입하는 것이다 :

    이 문제를 해결하는 올바른 방법은 다른 클래스 (의존성 주입)에 데이터베이스 객체를 삽입하는 것이다 :

    $db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
    include_once("pagi.php");
    
    $pagination = new Paginator($db);
    $records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`");
    
    class Paginator
    {    
        protected $db;
    
        // Might be better to use some generic db interface as typehint when available
        public function __construct(DB_MySQL $db)
        {
            $this->db = $db;
        }
    
        public function get_records($q) {
            $x = $this->db->query($q);
            return $this->db->fetch($x);
        }
    
    }
    

    당신이 그것을 해결할 수있는 또 다른 방법은 방법으로 그 용도를 데이터베이스 클래스의 인스턴스를 주입하는 것입니다 :

    $db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
    include_once("pagi.php");
    
    $pagination = new Paginator();
    $records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`", $db);
    
    class Paginator
    {
        public function get_records($q, DB_MySQL $db) {
            $x = $db->query($q);
            return $db->fetch($x);
        }
    
    }
    

    어떤 방법이 선택은 상황에 따라 달라집니다. 단 하나의 방법은 데이터베이스의 인스턴스를 필요로하는 경우 당신은, 방법에 주입 할 수 있습니다 그렇지 않으면 나는 클래스의 생성자에 주입한다.

    또한 내가 매기기에 pagi에서 클래스 이름을 바꾼 있습니다. 그것은 당신의 코드를 보는 다른 사람들 (재) 대한 명확한 때문에 매기기는 클래스에 대한 더 나은 이름 이럴입니다. 또한 내가 첫 글자를 대문자로 만든 있습니다.

    내가했던 또 다른 것은 당신이 사용하는 대신 "와일드 카드"*을 사용하는 필드를 선택하는 쿼리를 변경됩니다. 사람들 (재) 데이터베이스 및 / 또는 결과를 확인하지 않고 검색됩니다 어떤 필드를 정확히 알 수 코드를보기 : 이것은 내가 클래스 이름을 변경 한 같은 이유입니다.

    최신 정보

    대답은 내가 의존성 주입 경로를 이동하는 이유에 대해 대신의 목적은 글로벌 선언 토론에 상승을 주었기 때문에, 나는 세계 키워드를 통해 의존성 주입을 사용하는 이유를 명확히하고 싶습니다 : 당신이하는 방법 등이있을 때 :

    function get_records($q) {
        global $db;
    
        $x = $db->query($q);
        return $db->fetch($x);
    }
    

    위의 방법 어딘가에을 사용하는 경우는 클래스 나 메소드가 사용하는 $ DB에 의존한다는 것을 명확하지 않다. 따라서 그것은 숨겨진 의존성이다. 당신이 단단히 $의 DB 인스턴스 메소드 / 클래스 (따라서 DB_MySQL) 클래스를 결합했기 때문에 위가 나쁜 또 다른 이유이다. 당신이 어떤 점에서이 데이터베이스를 사용해야하는 경우. 이제 글로벌 $ DB2는 글로벌 $의 DB를 변경하는 모든 코드를 통과해야합니다. 당신은 다른 데이터베이스로 바로 스위치에 코드를 변경해야해서는 안됩니다. 이러한 이유로, 당신은하지 말아야 :

    function get_records($q) {
        $db = new DB_MySQL("localhost", "root", "", "test");
    
        $x = $db->query($q);
        return $db->fetch($x);
    }
    

    다시 말하지만,이 단단히 방법 / 클래스에 DB_MySQL 클래스 커플 숨겨진 의존성, 그리고. 이 때문에 그것은 매기기 클래스가 제대로 단위 테스트도 불가능하다. 대신 만 단위 (페이지 배열 클래스) 당신은 또한 동시에 DB_MySQL 클래스를 테스트를 테스트. 그리고 여러 밀접하게 결합 종속성을 무엇을 할 자격이 있습니까? 지금 당신은 갑자기 소위 단위 테스트와 몇 가지 클래스를 테스트하고 있습니다. 의존성 주입을 사용하는 경우 그래서 당신은 쉽게 테스트 목적 심지어 조롱 하나를 다른 데이터베이스 클래스로 전환, 또는 수 있습니다. 하나의 단위 테스트의 이점 외에, 그것은 또한 반드시 당신의 검사 결과가 빨리 마무리 할 것 (당신은 종속성 때문에 잘못된 결과를 얻는에 대해 걱정할 필요가 없습니다).

    어떤 사람들은 싱글 톤 패턴은 데이터베이스 개체에 대한 액세스를 얻을 수있는 올바른 방법이라고 생각 할 수 있지만,이 명확해야한다, 위의 내용을 모두 읽은, 싱글은 기본적으로 일을 글로벌 만드는 또 다른 방법입니다. 그것은 차이가있을 수 있지만, 따라서 동일한 특성과 글로벌과 같은 문제가있다.

  2. ==============================

    2.내가 할 종속성 모델이 좋은이 점에 동의하지만, 데이터베이스, 나는 개인적으로 데이터베이스 클래스의 모든 인스턴스에 사용할 수있는 정적 연결을 사용하고 난 하나를 필요로 할 때마다 쿼리에 인스턴스를 만들 수 있습니다. 다음은 그 예이다 :

    내가 할 종속성 모델이 좋은이 점에 동의하지만, 데이터베이스, 나는 개인적으로 데이터베이스 클래스의 모든 인스턴스에 사용할 수있는 정적 연결을 사용하고 난 하나를 필요로 할 때마다 쿼리에 인스턴스를 만들 수 있습니다. 다음은 그 예이다 :

    <?php
    //define a database class
    class DB {
        //the static connection.
        //This is available to all instances of the class as the same connection.
        private static $_conn;
    
        //store the result available to all methods
        private $result;
        //store the last query available to all methods
        private $lastQuery;
    
        //static connection function. connects to the database and stores that connection statically.       
        public static function connect($host, $user, $pass, $db){
            self::$_conn = mysqli_connect($host, $user, $pass, $db);
        }
    
        //standard function for doing queries. uses the static connnection property.
        public function query($query){
            $this->lastQuery = $query;
            $this->result = mysqli_query(self::$_conn, $query);
            //process result, return expected output.
        }
    }
    
    //create connection to the database, this connection will be used in all instances of DB class
    DB::connect('local', 'DB_USER', 'DB_PASS');
    
    //create instance to query
    $test = new DB;
    //do query
    $test->query("SELECT * FROM TABLE");
    
    //test function
    function foo(){
        //create instance to use in this function
        $bar = new DB;
        //do query
        $bar->query("SELECT * FROM OTHER_TABLE");
        //return results
        return $bar->fetchArray();
    }
    

    내가 어떤 기능, 방법 ... 등과 클래스의 로컬 인스턴스 내 모든 쿼리를 수행하는 것을 사용에서 내가 DB의 원하는 모든 인스턴스를 만들 수 있습니다 그런 식으로. 모든 인스턴스는 동일한 연결을 사용합니다.

    그러나주의 할 것은 이것은 단지 정의 클래스 당 데이터베이스에 하나의 연결을 허용하지만, 이것은 나에게 문제가되지 않습니다 그래서 나는 단지 하나를 사용한다는 것입니다.

  3. ==============================

    3.당신은 get_records 방법의 호출에 DB 접속 ($ dB)을 추가 할 수 있습니다 :

    당신은 get_records 방법의 호출에 DB 접속 ($ dB)을 추가 할 수 있습니다 :

    여기에 코드의 관련 라인은 다음과 같습니다 :

    첫 번째 파일 :

    $records = $pagination->get_records("SELECT * FROM `table`", $db);
    

    두 번째 파일 :

    public function get_records($q, $db) {
    
  4. ==============================

    4.다른 대답은 지금까지 확실히 (예를 들어, 당신이 그 객체가 메소드를 호출하기 전에 정의가 필요 것)이 당신의 캡슐화를 파괴하기 때문에 글로벌을 사용하는 것이 바람직하다.

    다른 대답은 지금까지 확실히 (예를 들어, 당신이 그 객체가 메소드를 호출하기 전에 정의가 필요 것)이 당신의 캡슐화를 파괴하기 때문에 글로벌을 사용하는 것이 바람직하다.

    이 방법 서명에 그 집행 또는 클래스를 사용하지하는 것이 훨씬 낫다.

  5. from https://stackoverflow.com/questions/11923272/use-global-variables-in-a-class by cc-by-sa and MIT license