我想在父类中实现单例模式,结果却踩了一个坑!

直接上代码

class A
{
    private static $instance;

    private function __construct(){}

    public static function getInstance(): static
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }
        return static::$instance;
    }
}

class X extends A
{

}

class Y extends A
{

}

X::getInstance();

Y::getInstance();
Fatal error: Uncaught TypeError: A::getInstance(): Return value must be of type Y, X returned in C:\Users\Administrator\Desktop\test.php:17
Stack trace:
#0 C:\Users\Administrator\Desktop\test.php(33): A::getInstance()
#1 {main}
  thrown in C:\Users\Administrator\Desktop\test.php on line 17
让PHP再次伟大
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
最佳答案

可以这样写:

<?php

class A
{
    private static $instances;

    private function __construct()
    {
    }

    public static function getInstance(): static
    {
        $class = static::class;

        if (!isset(static::$instances[$class])) {
            static::$instances[static::class] = new static;
        }

        return static::$instances[static::class];
    }
}

class X extends A
{
}

class Y extends A
{
}

$x = X::getInstance();

$y = Y::getInstance();


var_dump($x, $y);
1年前 评论
勇敢的心 (楼主) 1年前
讨论数量: 13

可以这样写:

<?php

class A
{
    private static $instances;

    private function __construct()
    {
    }

    public static function getInstance(): static
    {
        $class = static::class;

        if (!isset(static::$instances[$class])) {
            static::$instances[static::class] = new static;
        }

        return static::$instances[static::class];
    }
}

class X extends A
{
}

class Y extends A
{
}

$x = X::getInstance();

$y = Y::getInstance();


var_dump($x, $y);
1年前 评论
勇敢的心 (楼主) 1年前
sreio

file

1年前 评论

把变量 $instance 放到获取单列里面

1年前 评论

如果不需要之前调用过的实例,可以试试这样

class F
{
    private static $instance;

    private function __construct()
    {
    }

     /**
     * @return static
     * @author: chenyansong
     * time: 2022/8/31 15:30
     */
    public static function getInstance(): static
    {
        if (is_null(static::$instance)) {
            static::$instance = new static;
        }
        if (get_class(static::$instance) !== static::class) {
            static::$instance = new static;
        }
        return static::$instance;
    }
}
1年前 评论

static 和 self的区别

<?php

class A
{
    private static $instance;

    private function __construct(){}

    public static function getInstance(): self
    {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

class X extends A
{

}

class Y extends A
{

}

X::getInstance();

Y::getInstance();
1年前 评论
忆往昔弹指间 1年前
cccyzloong (作者) 1年前

这个我熟啊,因为我们经常调用模型,有时候懒得new,所以就在父类统一实现了静态实例,这样所有模型都能静态调用

<?php

namespace Company\Model;

use Think\Model;

abstract class CommonModel extends Model
{
    static $models = [];

    /**
     * @return $this
     */
    public static function getInstance()
    {
        $name = get_called_class();
        if (!isset(self::$models[$name])) {
            self::$models[$name] = new $name();
        }
        return self::$models[$name];
    }
}
1年前 评论
勇敢的心 (楼主) 1年前
陈先生 1年前

file

這個不能限制返回類型是static 當X::getInstance() 的時候 $instance 就是對象X了 如果在 Y::getInstance() 因為有返回類型的限制 必須要要返回Y對象 但是因為X::getInstance() 之後 $instance 就是對象X了 所以就報錯了 而且這種感覺有一個弊端就是$instance永遠是第一次調用getInstance的那個類的對象 可以向laravel的ioc容器那樣 用數組

1年前 评论

和通过trait实现比起来 哪种是更好的实践?

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!