调用 class 方法的 public 构造函数与调用另一个 class 方法的 class 方法有什么区别?

What is the difference between a public constructor which calls a class method and a class method that calls another class method?

我对 OO 编程有点陌生,无法理解为什么一种机制有效而另一种机制无效。

我创建了一个简单的 class,用于 return 一个 MySQL 数据库句柄。我尝试直接从构造函数 returning 句柄失败。但是在创建实例后,从 class 方法或 class(?) 方法成功。这是 class 定义和示例脚本

<?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. 为什么我不能直接从构造函数 return 句柄,因为它看起来与直接调用 class 方法非常相似?为什么构造函数调用 class 方法或我的脚本调用它很重要?

  2. 如果我用 PHP 的默认构造函数创建一个实例,我真的是在用 $db->create() 调用 class 方法吗?

我似乎在这里遗漏了一些基本概念。提前致谢!

您不能 return 在该上下文中构造函数的句柄,因为那样会违反 new 定义的行为。 new SomeClass(); 只会 return class 的一个实例,而不管在构造函数中调用了哪些其他方法。

__construct() 是无效方法。它不是打算到return任何东西1。这并不意味着其中的其他代码不会被执行,只是您的 return 在创建新对象的上下文中被忽略了。这是有道理的,因为构造函数的主要目的是提供一种将依赖项传递给对象的方法。有时它用于对象的附加 initialization/setup,但许多人认为除了将给定参数分配给对象的属性外,它不应该做任何其他工作。无论哪种方式,都不需要 return 任何东西。



1 可以 实际上显式地调用 __construct() 方法 你之后创建对象,然后它将像普通方法一样运行,您的 return 将起作用。

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

虽然这不是一件正常的事情,但我想不出有什么用处或需要它的情况。我只是想指出这是可能的。

Why can't I return the handle directly from a constructor when it seems so similar to calling the class method directly?

如果你能做到这一点,那么你就不会有 HMMDatabaseHandle 的实例;你会有一个 PDO 的实例。您将如何访问 HMMDatabaseHandle 提供的任何其他方法?


虽然我完全同意@Don't Panic 的回答,但我还需要指出您混合了静态方法和实例方法。

作为一般经验法则,如果您希望能够在不首先实例化对象的情况下调用方法,请使用 static 关键字。如果你想实际创建和使用一个对象,那么你可以像这样定义你class并使用$this->(或者$object->如果在class) 而不是 :: 来访问 实例 属性和方法。

<?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();
        }
    }
}

要实际执行此操作,您现在需要实例化新的 class。

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

最后,您可以使用一个技巧使您的构造函数 可链接 。只需将其括在括号中即可。

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