PHP ООП код не работает из-за синтаксических ошибок?

1

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

1) Я прочитал официальное руководство PHP по ООП (введение, основы, наследование, свойства и т.д.) Кажется, я честно не получаю что-то. Im на нем в течение нескольких часов и фиксировал несколько вещей, но появляются новые ошибки.

2) Я прочитал сообщения об ошибках Отсутствует аргумент 1 для Main :: __ construct() и Undefined variable: array. Это означает, что моя начальная переменная $ NULL.

3) Я сделал несколько поисков в stackoverflow, либо он не полностью связан или очень сложно для меня понять, что происходит, поскольку код примера настолько сложный (не лучший для стартера).

Мой вопрос: Почему приведенный ниже код не работает? Я бы очень признателен, почему он терпит неудачу и что я должен учитывать.

    class Main {
    protected $config;
    protected $start;

        function __construct($arr) {
            if(!isset($this -> start)) {
                if ($arr['secure']){
                    $this -> config = parse_ini_file('C:\xampp\htdocs\project\config.ini');
                    $this -> start = mysqli_connect($this -> config['host'], $this -> config['username'], 
                                                    $this -> config['password'], $this -> config['database']);
                }
                else {
                    $this -> start = mysqli_connect($arr['host'], $arr['username'], $arr['password'], $arr['database']);
                }
            }
            if($this -> start == false) {
                return mysqli_connect_error();
            }
        }
    }

$Main = new Main($array = ["host" => '', "username" => '', "password" => '', "database" => '', 
                           "errors" => false, "secure" => true]);

    class Test extends Main {
        public function sample() {
            $query = "SELECT id, user,
                      FROM users";
            $result = mysqli_query($Main -> start , $query);
            $row = mysqli_fetch_array($result);
            echo $row['user'];
        }
    }       

    $x = new Test();

    $x -> sample();
Теги:
scope
oop
inheritance

4 ответа

3
Лучший ответ

Итак, что происходит во время выполнения:

$Main = new Main(...);

Хорошо, вы можете получить соединение там, если эти детали заполнены, но есть проблема при определении того, было ли вы успешное соединение или нет. См. Ниже для получения дополнительной информации, но $Main важно отметить сейчас.

$x = new Test();

Test класса расширяет ваш класс Main. Поэтому ваш Test класса наследует конструктор Main класса, для которого требуется аргумент. Аргумент не указан, поэтому он генерирует предупреждение.

Чтобы учесть это, сделайте $arr необязательным, если вы не всегда будете его передавать:

function __construct($arr = array())

Затем проверьте, существует ли он, используя isset в индексе:

if(isset($arr['secure'])) // ...

Ускоренная перемотка вперед, поскольку вы не предоставили $arr, вы не сможете успешно подключиться к своей БД. Согласно mysqli::__construct(), который mysqli_connect является псевдонимом, он попытается вернуть объект ("который представляет соединение с сервером MySQL").

Теперь взгляните на эти строки:

$this -> start = mysqli_connect( ... )
// ...
if ($this -> start == false) {

Вы должны проверить атрибут return connect_error (или mysqli_connect_error()), чтобы проверить, работает ли соединение или нет.

Благодаря приведенным ниже комментариям, вы также должны проверить ложное назначение, поскольку mysqli_connect, что mysqli_connect генерирует предупреждение и возвращает false, даже если оно не показано в документах PHP.

Продолжим.

$x -> sample();

Test::sample использует mysqli_query который ожидает соединение с базой данных в качестве первого аргумента. Вы $Main->start это, передав $Main->start.

К сожалению, $Main не входит в вашу область переменных и недоступен изнутри этого метода. Что вам нужно сделать, это $this->start.

Фактически, если это единственная причина, по которой вы создали экземпляр $Main, тогда вам не нужно в этот момент. Вместо этого передайте массив сведений о соединении до new Test().

Здесь два решения:

  1. Передайте данные вашего соединения с DB до $x = new Test(); Экземпляр затем подключится к БД по назначению и сможет выполнить запрос.
  2. Отделите класс Test от класса Main и передайте экземпляр класса Main через конструктор класса Class. Вероятно, лучший вариант. Если ваш тест предназначен для вашего запроса, у него нет расширения Main, создайте свой объект подключения к базе данных (new Main(..)), а затем передайте его в new Test($Main). В вашем классе Test создайте конструктор, который принимает основной класс в качестве аргумента:

     public function __construct(Main $main)
     {
         $this->db = $main;
     }
    

Разрешить доступ к вашему объекту подключения, добавив public атрибут $main $start или создав функцию getter (например, getConnection()), а затем используйте, чем в вашем запросе:

$result = mysqli_query($this->db->getConnection(), $query);

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

  • 0
    Это действительно подробно. Я собираюсь прочитать это сейчас. Это немного сложно из JS OOP, поэтому я очень ценю это.
  • 0
    Объекты могут быть NULL, хотя я могу сказать == NULL?
Показать ещё 3 комментария
0

Ознакомьтесь с комментариями ниже

//I suggest to make this class abstract to make sure
//php doesn't let you to instantiate it directly as you did before 

    abstract class Main {

        protected $config;
        protected $start;

            function __construct($arr) {
                if(!isset($this -> start)) {
                    if ($arr['secure']){
                       $this -> config = parse_ini_file('C:\xampp\htdocs\project\config.ini');
                        $this -> start = mysqli_connect($this -> config['host'], $this -> config['username'], 
                                                        $this -> config['password'], $this -> config['database']);
                    }
                    else {
                        $this -> start = mysqli_connect($arr['host'], $arr['username'], $arr['password'], $arr['database']);
                    }
                }
                if($this -> start == false) {
                    return mysqli_connect_error();
                }
            }
        }

        class Test extends Main {
            public function sample() {
                $query = "SELECT id, user,
                          FROM users";

//Here you should use $this instead of $Main as you can access protected 
//properties of the parent from the child class. 

                $result = mysqli_query($this -> start , $query);
                $row = mysqli_fetch_array($result);
                echo $row['user'];
            }
        }       

//Instantiate Test class instead of Main as it inherits Main anyway
//Your code also had a typo in the constructor argument.

       $x = new Test(array("host" => '', "username" => '', "password" => '', "database" => '', "errors" => false, "secure" => true));

       $x -> sample();

Пожалуйста, не то, что я не проверял часть mysql вашего кода - просто структура ООП

0
$result = mysqli_query($Main -> start , $query);

в

$result = mysqli_query($this -> start , $query);

Это, по крайней мере, устраняет синтаксическую ошибку. $this интроспективная переменная, она всегда относится к текущей области экземпляров.

  • 0
    Но тогда он не использует соединение с новым объектом
  • 0
    $ Main = новый Main
Показать ещё 5 комментариев
0

Вы работаете с двумя разными экземплярами.

// This is one instance
$Main = new Main([...]);

// This is a different instance.
$test = new Test();

Расширение класса не означает, что оно получает значения из существующих экземпляров класса. Это означает, что он получает те же методы (и свойства по умолчанию).

Поэтому ваш тест класса получает тот же конструктор, что и Main, что означает, что вам нужно отправить массив в Test, чтобы иметь возможность использовать его экземпляр. В вашем примере нет оснований для непосредственного создания Main непосредственно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню