Intereting Posts
Laravel 4: Заголовок разбивки и сортировки Параллельное использование постоянного PHP-сокета wordpress 3.8.1 категория страница 2 ошибка 404 не найден / пользовательский тип сообщения PHP Если заявление с несколькими условиями Предупреждение: mysql_num_rows () ожидает, что параметр 1 будет ресурсом, массив указан в Как заставить браузер кэшировать изображения с помощью php? CData в simplexml открыт из XMLReader Ошибка WordPress при разработке плагина – «У вас недостаточно прав для доступа к этой странице». CakePHP – Как я могу определить маршрут к файлу non-cakephp, который не имеет каких-либо контроллеров, связанных с ним? Необходимо войти в систему на странице https Является ли это эффективным кодированием антиспама? установить PHP cookie на клик Каталог загрузки Vimeo PHP Как проверить, активен ли IP-адрес посетителя или онлайн? Блокируйте прямой доступ к файлам PHP и разрешите json

Использовать глобальные переменные в классе

Я пытаюсь создать класс pagination и использовать переменную извне класса.

Но это дает мне фатальную ошибку «Вызов функции-функции члена () для не-объекта».

Это индексный файл:

$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); } } 

Можно ли использовать эту переменную извне класса внутри класса, не создавая новую внутри класса?

Правильный способ решения этой проблемы – ввести объект базы данных в другой класс ( инъекция зависимостей ):

 $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 для класса, потому что для других людей (re) для вашего кода ясно. Также обратите внимание, что я сделал первую букву в верхнем регистре.

Еще одна вещь, которую я сделал, – это изменить запрос, чтобы выбрать поля, которые вы используете, вместо использования «подстановочного знака» * . Это по той же причине, что я изменил имя класса: люди (повторно), просматривающие ваш код, точно узнают, какие поля будут извлечены без проверки базы данных и / или результата.

Обновить

Поскольку ответ привел к обсуждению вопроса о том, почему я бы пошел на путь внедрения зависимостей вместо объявления объекта global , я хотел бы уточнить, почему я бы использовал инъекцию зависимостей над global ключевым словом: когда у вас есть такой метод, как:

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

Когда вы используете вышеописанный метод где-то, неясно, использует ли класс или метод значение $db . Следовательно, это скрытая зависимость. Другая причина, почему это плохо, – это то, что вы тесно DB_MySQL класс $db (таким образом, DB_MySQL ) с этим методом / классом. Что делать, если вам нужно использовать 2 базы данных в какой-то момент. Теперь вам придется пройти весь код, чтобы сменить global $db на global $db2 . Вам не нужно менять код, чтобы переключиться на другую базу данных. По этой причине вы не должны делать:

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

Опять же, это скрытая зависимость и плотно DB_MySQL класс DB_MySQL с методом / классом. Из-за этого также невозможно правильно протестировать класс Paginator . Вместо тестирования только единицы (класс Paginator ) вы также тестируете класс DB_MySQL одновременно. А что, если у вас несколько тесно связанных зависимостей? Теперь вы неожиданно тестируете несколько классов с помощью так называемых модульных тестов. Поэтому при использовании инъекции зависимостей вы можете легко переключиться на другой класс базы данных или даже на насмешку для тестирования. Помимо преимуществ тестирования только одного устройства (вам не нужно беспокоиться о неправильных результатах из-за зависимостей), он также гарантирует, что ваши тесты будут быстро завершены.

Некоторые люди могут подумать, что шаблон Singleton – это правильный способ получить доступ к объекту базы данных, но должно быть ясно, прочитав все вышеизложенное, одноэлемент – это просто еще один способ сделать вещи global . Он может выглядеть по-другому, но он имеет точные характеристики и, следовательно, те же проблемы, что и global .

Хотя я согласен с тем, что модель зависимости хороша, для базы данных я лично использую статическое соединение, доступное для всех экземпляров класса базы данных, и экземпляры экземпляров для запроса, когда мне это нужно. Вот пример:

 <?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-соединение ( $db ) к вызову метода get_records :

Вот только соответствующие строки кода:

Первый файл:

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

Второй файл:

 public function get_records($q, $db) { 

Остальные ответы на сегодняшний день, безусловно, предпочтительнее использования глобального, поскольку это разрушит вашу инкапсуляцию (например, вам нужно будет определить этот объект до вызова этого метода).

Гораздо лучше применять это в сигнатуре метода или не использовать класс.

Используйте шаблон singleton и введите DB_MySQL со статическим экземпляром!