我有这样的代码,可能写得很好,也可能写得不好:)。我试图理解为什么当我创建一个ojbect的新实例时,即使我取消设置它,它也不会运行父构造。
class core
{
protected $db;
private static $dsn = 'mysql:host=localhost;dbname=tracking';
private static $user = 'root';
private static $pass = 'root';
private static $instance;
public function __construct () {
$this->db = new PDO(self::$dsn,self::$user,self::$pass);
error_log("database connection called");
}
public static function getInstance(){
if(!isset(self::$instance)){
$object= __CLASS__;
self::$instance=new $object;
}
return self::$instance;
}
}
class Site extends core{
function __construct(){
global $argc, $argv;
$this->db_core = core::getInstance();
$this->pdo = $this->db_core->db;
$this->track_id = $argv[1];
error_log("SITE construct called!");
}
function save_to_db(){
//stuff
}
}
以下代码将只记录一次"调用的数据库连接"。
1
$site = new Site;
unset($site);
$site = new Site;
2
$site = new Site;
$site = new Site;
3
$site = new Site;
$site_new = new Site;
我之所以希望每次创建新实例时都调用数据库,是因为这是一个cli脚本,可以在while
循环中运行数小时,如果超过了MySQL的wait_timeout,$site->save_to_db()
将不会执行任何操作,因为"MySQL服务器已经离开"。那么它是如何工作的呢?为什么不为新实例调用父对象的构造,或者当我取消设置并重新启动它时?
这是一个棘手的问题,您正在扩展看起来像singleton的东西。
当您在子类中设置构造函数时,父类的构造函数永远不会被调用。
但是在子类的同一个构造函数中,您正在初始化您的singleton,所以当您调用:时
self::$instance=new $object;
您可以直接调用core
类的构造函数。由于它是作为一个单例设置的,所以这种情况只会发生一次。
我不建议这样做,singleton是伪装的全局变量(让测试变得痛苦…),如果你决定这样使用它,你不应该扩展它,而是在你需要的地方调用你的静态singleton db实例(就像你在子类的构造函数中实际做的那样…)。
您最好实例化一个数据库对象,并将其传递给需要它的对象的构造函数(依赖注入)。
顺便说一句,如果您想在子类中调用父类的构造函数,那么您需要在子类的构造函数中使用parent::__construct();
。
core
类就是所谓的"Singleton"。它创建自己的一个实例,并使其全局可用。singleton的全部意义在于它只能有一个实例
当实例化$site
、取消设置或再次实例化时,core
类的self::$instance
属性保持不变。这是因为它是一个静态属性,它们不绑定到实例,而是类成员,是持久的(当脚本运行时)。
顺便说一下,以下代码过于复杂:
$object= __CLASS__;
self::$instance=new $object;
也可以是:
self::$instance = new self();
更短更明显。