仅当重新初始化继承类中的实例变量时,PHP 中使用单例模式的类继承才有效。但为什么?

2024-04-10

我有一个带有单例函数的主类实例()和相关变量$实例。现在我创建几个子类并让主类继承。我没有重新定义单例函数和变量,因为继承很有用。不幸的是,每个实例都指向第一个子类。仅当在子类中$实例变量被初始化为null它有效,但为什么呢?有了关键词static并不是self,范围应保留在子类中。

这是源代码,可以更好地理解我的意思:

// PHP Version 7.0
// Don't work as expected:

class base1
{
    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null;

    /*
     * For Singleton Pattern
     */
    public static function instance() {

        if ( null == static::$instance ) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    public function test()
    {
        $test = "base1";
        var_dump($test);
    }
}

class sub11 extends base1
{
    public function test()
    {
        $test = "base1 -> sub11";
        var_dump($test);
    }
}

class sub12 extends base1
{
    public function test()
    {
        $test = "base1 -> sub12";
        var_dump($test);
    }
}

$sub11 = sub11::instance();
$sub12 = sub12::instance();
$sub11->test();
$sub12->test();
// Output:
// string(14) "base1 -> sub11"
// string(14) "base1 -> sub11"  // It's not different!!!

// Work as expected:

class sub21 extends base1
{

    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null;  // Is needed, but why?

    public function test()
    {
        $test = "base1 -> sub21";
        var_dump($test);
    }
}

class sub22 extends base1
{
    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null; // Is needed, but why?

    public function test()
    {
        $test = "base1 -> sub22";
        var_dump($test);
    }
}

$sub21 = sub21::instance();
$sub22 = sub22::instance();
$sub21->test();
$sub22->test();
// Output:
// string(14) "base1 -> sub21"
// string(14) "base1 -> sub22"  // This is correct !

在你的第一部分它正在工作correct和预期的一样。两个班sub11 and sub12 using base1的字段来存储实例。因此,第一个已启动的实例被放置在那里并防止其他人覆盖已经创建的实例。

在第二部分中,您为每个后代类指定了个人静态存储字段,因此它们不使用基类字段,而是使用自己的字段(它与父字段重叠,因为使用相同的名称)。

简而言之,第一对后代类使用base1::$instance检查并创建实例。第二对使用自己的字段,sub21::$instance and sub22::$instance为了这个任务。

您可以通过丢弃后期静态绑定来防止这种情况base1 class:

class base1
{
    /*
    * Instance of class
    * mixed
    */
    protected static $instance = null;

    /*
     * For Singleton Pattern
     */
    public static function instance() {
        if ( null == self::$instance ) {
        //           ^ self instead of static
            self::$instance = new static();
        //  ^ self instead of static
        }

        return self::$instance;
        //     ^ self instead of static
    }

    public function test()
    {
        $test = "base1";
        var_dump($test);
    }
}

我真的建议你阅读后期静态绑定 http://php.net/manual/en/language.oop5.late-static-bindings.php和之间的区别self and static关键词。

UPDv1:

如果您仍然需要仅获取每个后代类的一个实例,您可以将 singleton 方法更改为如下所示:

class base1
{
    /*
    * Instances of descendant classes
    * array
    */
    protected static $instances = [];

    /*
     * For Singleton Pattern
     */
    public static function instance() {
        if (empty(self::$instances[static::class])) {
            $instance = new static();

            self::$instances[static::class] = $instance;
        } else {
            $instance = self::$instances[static::class];
        }

        return $instance;
    }

    public function test()
    {
        $test = "base1";
        var_dump($test);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅当重新初始化继承类中的实例变量时,PHP 中使用单例模式的类继承才有效。但为什么? 的相关文章

  • 将字符串的第一个字母大写(前面带有特殊字符) - PHP

    我想将字符串大写 例如 hello 我希望我的函数返回 Hello 我尝试过使用 regex 和 preg match 但没有运气 这是我之前的问题 与此相关 preg match 正在匹配两个字符 而它应该只匹配一个字符 https st
  • 如何让 Laravel“确认”验证器将错误添加到确认字段?

    默认情况下 Laravel 确认 验证器将错误消息添加到原始字段 而不是通常包含确认值的字段 password gt required confirmed min 8 是否有任何简单的方法来扩展验证器或使用一些技巧来强制它始终在确认字段而不
  • php 中 php.ini 的 log_errors 和 error_log

    我正在尝试通过 php ini 更改 php ini 中的设置 我的问题是 当出现错误时 它不会放入文件 error log txt 中 那么我做错了什么 这是我的代码 Settings for php ini ini set sessio
  • 如何改进 PHP 分页算法?

    我正在研究 PHP 中的分页算法 我可以猜测它需要改进的空间 所以我想对如何改进它有一些想法 无论是从 UI UX 的角度清理代码本身 还是你能想到的任何其他东西 该算法应输出如下所示的分页 1 2 3 6 7 8 97 98 99 or
  • 如何将JS/CSS文件包含到Slim框架的模板中?

    我正在使用 Slim 框架开发一个简单的网络应用程序 我遇到了一个可能很简单的问题 我想将静态文件 CSS 和 Javascript 包含到我的模板中 我的项目文件夹结构如下 index php lt where all the routi
  • 如何在 SQLite 中获取最后插入的 ID?

    SQLite 中是否有任何内置函数可以获取最后插入的行 ID 例如 在 mysql 中我们有LAST INSERT ID 这种功能 对于 sqlite 任何可用于执行相同过程的函数 请帮我 Thanks SQLite 这可以使用SQLite
  • python多重继承,调用基类函数

    我只是尝试在 python 中进行多重继承 我想出了这个 class ParentOne def foo self print ParentOne foo is called class ParentTwo def foo self pri
  • 提交简单 PHP 表单时出现禁止错误

    我有一个不复杂的问题 这似乎比应有的更复杂 我有一个简单的表单 用于向网站添加内容 有些字段需要输入html 然而 当您在表单的不同部分输入某些 html 元素时 它会认为它讨厌您并抛出禁止的 403 错误 这是下面的表格
  • PHP FTP_PUT 上传到目录

    我正在自学PHP 一本名为 PHP完全参考 PHP5 2 的书 我目前正在使用第 11 章 FTP 上传 删除 makedir 等 但遇到了一些本书未涵盖的问题 根据我的教科书 这是上传到服务器的简单代码 connect ftp conne
  • 有没有办法在javascript中代理(拦截)一个类的所有方法?

    我希望能够在类本身的构造函数内代理类的所有方法 class Boy constructor proxy logic do something before each call of all methods inside class like
  • 如何在PHP中完成http响应并进行进一步处理?

    就我而言 我需要向客户端回显一个标志并发送一封电子邮件 现在客户端需要等待电子邮件发送 但我想把这两个步骤分开 该怎么做呢 你可以看一下异步运行 PHP 任务 https stackoverflow com questions 858883
  • PHP 多个 Ajax 请求:第一个请求阻止第二个请求

    我在一页上有 2 个 ajax 请求 我运行了第一个请求并单独启动了第二个请求 但第二个在第一个运行后停止工作 第一次结束后继续 第一个请求需要很长时间 大约 30 60 秒 此时我需要第二个请求来显示日志第一个请求发生的情况 我尝试使用
  • json_decode 到自定义类

    是否可以将 json 字符串解码为 stdClass 以外的对象 不是自动的 但你可以按照老式的路线来做 data json decode json true class new Whatever foreach data as key g
  • 很简单的PHP加法问题

    我想我已经关注这个问题太久了 为什么这段代码打印 no 它应该打印 yes 不是吗 我在 PHP 5 3 和 PHP 5 2 上尝试过 都打印 no See 比较浮点数 http www cygnus software com papers
  • 如何使用 Google Calendar API 和官方 PHP 库创建全天活动?

    我有这个代码 event new Event event gt setSummary event summary event gt setLocation event location start new EventDateTime sta
  • FPM 与 apache2 无法工作(权限被拒绝)

    我正在尝试使用 apache fastcgi 和 fpm 设置一个 Debian Web 服务器 但我越来越恼火 一旦我停用 mod php 我就会收到以下错误 2014 年 5 月 22 日星期四 12 16 10 错误 客户端 xxx
  • 将 Base64 字符串转换为图像文件? [复制]

    这个问题在这里已经有答案了 我正在尝试将我的 Base64 图像字符串转换为图像文件 这是我的 Base64 字符串 http pastebin com ENkTrGNG http pastebin com ENkTrGNG 使用以下代码将
  • 如何检测iPhone是否有视网膜显示屏?

    如何检测 iPhone 是否配备视网膜显示屏 有靠谱的办法吗 要么是纯 PHP 要么最好是 Zend Framework 方式来执行此操作 我通过这个弄清楚了 var retina window devicePixelRatio gt 1
  • MVC 框架中的缓存策略?

    我编写了自己的小型 PHP MVC 框架 现在正在探索 PHP MVC 框架中的缓存策略 我正在考虑可以缓存什么 在哪里以及如何缓存 我的框架是简单的MVC框架 我有前端控制器 它启动应用程序 注册类自动加载 设置 php 运行时指令 最后
  • 将 Hbase 与 PHP 集成 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经安装了 Hbase 现在我正在寻找一些 PHP 库来将 hbase 与 PHP 集成 我尝试了 2 个库 第一个是我尝试与 th

随机推荐