복붙노트

클래스에서 전역 변수 사용

PHP

클래스에서 전역 변수 사용

페이지 매김 클래스를 만들고 클래스 밖에서 변수를 사용하려고합니다.

하지만 그것은 나에게 치명적인 오류 "구성원 함수 쿼리 () 비 - 개체에 대한 호출"을주고있어.

다음은 색인 파일입니다.

$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에서 Paginator로 변경했습니다. Paginator는 다른 사람 (코드)을 보는 것이 분명하기 때문에 클래스에 대한 더 나은 이름의 IMHO입니다. 또한 첫 글자를 대문자로 만들었습니다.

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

    최신 정보

    그 대답은 왜 객체를 전역으로 선언하는 대신에 의존성 주입 라우트를 사용하는지에 대한 논의를 야기했기 때문에 전역 키워드에 대한 의존성 주입을 사용하는 이유를 명확히하고자합니다. 다음과 같은 메소드가있을 때 :

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

    위의 방법을 어딘가에 사용하면 클래스 또는 메소드 사용이 $ db에 종속된다는 것이 확실하지 않습니다. 따라서 숨겨진 종속성입니다. 위의 이유가 또 다른 이유는 $ db 인스턴스 (따라서 DB_MySQL) 클래스를 해당 메소드 / 클래스에 밀접하게 연결했기 때문입니다. 어떤 시점에서 2 개의 데이터베이스를 사용해야하는 경우에는 어떻게해야합니까? 이제 전역 $ db를 global $ db2로 변경하기 위해 모든 코드를 검토해야합니다. 다른 데이터베이스로 전환하기 위해 코드를 변경하지 않아도됩니다. 이러한 이유로 다음과 같이해서는 안됩니다.

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

    다시 말하지만 이것은 숨겨진 종속성이며 DB_MySQL 클래스를 메서드 / 클래스와 밀접하게 연결합니다. 이 때문에 Paginator 클래스를 제대로 단위 테스트하는 것도 불가능합니다. 유닛 (Paginator 클래스) 만 테스트하는 대신 DB_MySQL 클래스도 동시에 테스트합니다. 그리고 밀접하게 결합 된 종속성이 여러 개 있다면 어떨까요? 이제 당신은 갑자기 단위 테스트라고 불리는 여러 클래스들을 테스트하고 있습니다. 따라서 의존성 주입을 사용하면 테스트 목적으로 다른 데이터베이스 클래스 또는 조롱 된 데이터베이스 클래스로 쉽게 전환 할 수 있습니다. 종속성으로 인해 잘못된 결과를 얻는 것에 대해 걱정할 필요가없는 단 하나의 단위 만 테스트하는 이점 외에도 테스트가 빠르게 완료 될 것입니다.

    어떤 사람들은 Singleton 패턴이 데이터베이스 객체에 접근 할 수있는 올바른 방법이라고 생각할 수 있습니다. 그러나 위의 모든 것을 읽은 후, 싱글 톤은 기본적으로 물건을 글로벌하게 만드는 또 다른 방법입니다. 그것은 다르게 보일지도 모르지만, 그것은 똑같은 특성을 가지고 있으며 따라서 세계와 동일한 문제를 가지고 있습니다.

  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-connection ($ db)을 추가 할 수 있습니다.

    get_records 메소드 호출에 db-connection ($ db)을 추가 할 수 있습니다.

    다음은 관련 코드 행뿐입니다.

    첫 번째 파일 :

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

    두 번째 파일 :

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

    4.지금까지의 다른 답변들은 캡슐화를 망칠 것이므로 (예를 들어 그 메소드를 호출하기 전에 그 객체를 정의해야 할 필요가 있기 때문에) 전역을 사용하는 것이 좋습니다.

    지금까지의 다른 답변들은 캡슐화를 망칠 것이므로 (예를 들어 그 메소드를 호출하기 전에 그 객체를 정의해야 할 필요가 있기 때문에) 전역을 사용하는 것이 좋습니다.

    메서드 시그니처에 적용하거나 클래스를 사용하지 않는 것이 훨씬 좋습니다.

  5. ==============================

    5.싱글 톤 패턴을 사용하고 DB_MySQL에 정적 인스턴스를 삽입하십시오!

    싱글 톤 패턴을 사용하고 DB_MySQL에 정적 인스턴스를 삽입하십시오!

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