В чем разница между открытым конструктором, который вызывает метод класса, и методом класса, который вызывает другой метод класса? - PullRequest
0 голосов
/ 23 октября 2019

Я немного новичок в ОО-программировании, и мне трудно понять, почему один механизм работает, а другой нет.

Я создал простой класс, который должен возвращать дескриптор базы данных MySQL. Моя попытка вернуть дескриптор непосредственно из конструктора не удалась. Но происходит успешно либо из метода класса, либо из метода класса (?) После создания экземпляра. Вот определение класса и пример скрипта

<?php

class HMMDatabaseHandle {

        private static $configfile = "config.json";

// uncomment for test 1
//      public function __construct () {
//              return self::get_handle_admin();
//      }

        public static function create() {
                return self::get_handle_admin();
        }

        private static function get_handle_admin() {
                $config = json_decode(file_get_contents(self::$configfile));
                $dbhost = $config->database->dbhost;
                $dbname = $config->database->dbname;
                $dbuser = $config->database->dbuser;
                $dbpass = $config->database->dbpass;

                try {
                        return new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
                }
                        catch(PDOException $e) {
                        echo $e->getMessage();
                }
        }
}

?>

А вот тестовый скрипт, который я использую:

<?php
require_once 'HMMDatabaseHandle.php';

// Test 1 - fails (uncomment constructor func) at call to prepare() with:
// PHP Fatal error:  Call to undefined method HMMDatabaseHandle::prepare()
//$dbh = new HMMDatabaseHandle();

// Test 2 - works when class creates default constructor
// i.e. no explicit __construct() func
// Fetching data from executed query is fine
//$db = new HMMDatabaseHandle();
//$dbh = $db->create();

// Works using static class methods rather than instance
$dbh = HMMDatabaseHandle::create();

$sth = $dbh->prepare('select data_title,track_id from master');
$sth->execute();
while($row = $sth->fetch(PDO::FETCH_ASSOC)) {
   ...
}

Мои вопросы:

  1. Почему я не могу вернуть дескриптор напрямую из конструктора, когда он кажется очень похожим на прямой вызов метода класса? Почему имеет значение, вызывает ли конструктор метод класса или мой скрипт вызывает его?

  2. Если я создаю экземпляр с конструктором PHP по умолчанию, действительно ли я вызываю метод класса с помощью $ db-> create ()?

Кажется, мне здесь не хватает фундаментальной концепции. Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 23 октября 2019

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

Если бы вы смогли это сделать, вы бы не смоглине имеет экземпляра HMMDatabaseHandle;у вас будет экземпляр PDO. Как бы вы получили доступ к любым другим методам, которые предоставляет HMMDatabaseHandle?


Хотя я полностью согласен с ответом @ Don't Panic, я должен также указать, что вы смешиваете статические методы и методы экземпляра.

Как правило, используйте ключевое слово static, если вы хотите иметь возможность вызывать метод, не создавая экземпляр объекта в первую очередь. Если вы действительно хотите создать и использовать объект , то вы можете определить свой класс следующим образом и использовать $this-> (или $object->, если он вне класса) вместо :: для доступа к экземпляр свойства и методы.

<?php
class HMMDatabaseHandle
{

    private $configfile = "config.json";


    public function __construct()
    {
        // You're not initializing anything in here, so this constructor is optional.
    }

    public function create()
    {
        return $this->get_handle_admin();
    }

    private function get_handle_admin()
    {
        $config = json_decode(file_get_contents($this->configfile));
        $dbhost = $config->database->dbhost;
        $dbname = $config->database->dbname;
        $dbuser = $config->database->dbuser;
        $dbpass = $config->database->dbpass;

        try {
            return new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
        }
        catch (PDOException $e) {
            echo $e->getMessage();
        }
    }
}

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

$dbManager = new HMMDatabaseHandle();
$handle = $dbManager->create();

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

$handle = (new HMMDatabaseHandle())->create();
2 голосов
/ 23 октября 2019

Вы не можете вернуть дескриптор из конструктора в этом контексте, потому что это нарушило бы определенное поведение new. new SomeClass(); будет только когда-либо возвращать экземпляр класса, независимо от того, какие другие методы вызываются в конструкторе.

__construct() - это метод void. не предназначен для возврата чего-либо 1 . Это не означает, что другой код в нем не выполняется, просто ваш return игнорируется в контексте создания нового объекта. Это имеет смысл, поскольку основной целью конструктора является предоставление средств для передачи зависимостей объекту. Иногда он используется для дополнительной инициализации / настройки объекта, но многие люди считают, что он не должен выполнять какую-либо работу, кроме присвоения заданных аргументов свойствам объекта. В любом случае, ему не нужно возвращать что-либо.



1 Вы можете фактически позвонить__construct() метод явно после вы создаете объект, и тогда он будет вести себя как обычный метод, и ваш return будет работать.

$db = new HMMDatabaseHandle();
$dbh = $db->__construct();
var_dump($dbh);  // PDO Object

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

...