【问题标题】:Is it possible to create static classes in PHP (like in C#)?是否可以在 PHP 中创建静态类(如在 C# 中)?
【发布时间】:2010-10-02 21:21:22
【问题描述】:

我想在 PHP 中创建一个静态类并让它像在 C# 中一样运行,所以

  1. 第一次调用类时会自动调用构造函数
  2. 无需实例化

这种东西……

static class Hello {
    private static $greeting = 'Hello';

    private __construct() {
        $greeting .= ' There!';
    }

    public static greet(){
        echo $greeting;
    }
}

Hello::greet(); // Hello There!

【问题讨论】:

  • 您能简要解释一下静态类的行为吗?它是实用程序的实现吗?
  • 只是发表我自己的观点,但根据我在 PHP 方面的经验,出于理智、可测试性和可扩展性的考虑,静态类应该几乎完全是无状态的,提供比功能更类似于编程的 API一个面向对象的,通常最好用作完全实例化对象的可访问性外观或帮助程序或类似构造的实用程序包装器,如果它们甚至被使用的话。

标签: php design-patterns oop static


【解决方案1】:

您可以在 PHP 中使用静态类,但它们不会自动调用构造函数(如果您尝试调用 self::__construct(),则会收到错误消息)。

因此,您必须创建一个initialize() 函数并在每个方法中调用它:

<?php

class Hello
{
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>

【讨论】:

  • 我经常这样做只是为了将所有功能打包在一个地方。 IE 实用程序::doSomethingUseful();
  • Therefore you'd have to create an initialize() function and call it in each method:相比,将initialize设为公共函数并在类声明后立即调用它会更容易。
  • 我知道这已经很老了,但是现在你可以使用魔法__callStatic,所以当你调用任何静态方法或任何东西时,它会首先调用__callStatic,你可以在那里查看它是否被初始化然后做self::$method 或任何你打电话的事情。如果它仍然直接调用该方法,请尝试将所有内容更改为私有并在那里查看。
  • 如果两个线程同时调用greet会发生什么?由于没有同步,不会初始化被调用两次(在这种情况下是可以的,但在许多其他情况下不会)。还是php像node一样是单线程非抢占式的?
  • 喜欢你的做法。太棒了。
【解决方案2】:

除了 Greg 的回答,我建议将构造函数设置为私有,这样就不可能实例化该类。

所以在我看来,这是一个基于 Greg 的更完整的示例:

<?php

class Hello
{
    /**
     * Construct won't be called inside this class and is uncallable from
     * the outside. This prevents instantiating this class.
     * This is by purpose, because we want a static class.
     */
    private function __construct() {}
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>

【讨论】:

  • 这是一个很好的方法,但是如果您的单例继承自某些需要公共构造函数的对象,则无法实现构造函数。
  • @EricHerlitz 这个问题不是关于单例,而是关于静态类。为什么要创建一个继承自要实例化的类的静态类?
  • 同样将类声明为抽象类,防止它被实例化,但仍然允许调用静态方法。
【解决方案3】:

你可以拥有那些类似“静态”的类。但我想,缺少了一些非常重要的东西:在 php 中你没有应用程序周期,所以你不会在整个应用程序中获得真正的静态(或单例)......

Singleton in PHP

【讨论】:

  • 静态类和单例只是两种不同的东西。
【解决方案4】:
final Class B{

    static $staticVar;
    static function getA(){
        self::$staticVar = New A;
    }
}

b 的结构称为 singeton 处理程序,您也可以在 a 中执行此操作

Class a{
    static $instance;
    static function getA(...){
        if(!isset(self::$staticVar)){
            self::$staticVar = New A(...);
        }
        return self::$staticVar;
    }
}

这是单例使用 $a = a::getA(...);

【讨论】:

    【解决方案5】:

    我通常更喜欢编写常规的非静态类并使用工厂类来实例化对象的单个 (sudo static) 实例。

    这样构造函数和析构函数正常工作,如果我愿意,我可以创建额外的非静态实例(例如第二个数据库连接)

    我一直使用它,对于创建自定义数据库存储会话处理程序特别有用,因为当页面终止时,析构函数会将会话推送到数据库。

    另一个优点是您可以忽略调用顺序,因为一切都将按需设置。

    class Factory {
        static function &getDB ($construct_params = null)
        {
            static $instance;
            if( ! is_object($instance) )
            {
                include_once("clsDB.php");
                $instance = new clsDB($construct_params);   // constructor will be called
            }
            return $instance;
        }
    }
    

    数据库类...

    class clsDB {
    
        $regular_public_variables = "whatever";
    
        function __construct($construct_params) {...}
        function __destruct() {...}
    
        function getvar() { return $this->regular_public_variables; }
    }
    

    任何你想用的地方只要调用...

    $static_instance = &Factory::getDB($somekickoff);
    

    然后将所有方法视为非静态的(因为它们是)

    echo $static_instance->getvar();
    

    【讨论】:

    • 这实际上是一个单例模式的实现,并且真的不应该使用 - 坚持使用依赖注入,它是可测试的并且易于调试。
    • 你能举个例子说明如何使用依赖注入来解决这个问题,以及如何使它更易于测试吗?
    【解决方案6】:

    对象不能静态定义 但这有效

    final Class B{
      static $var;
      static function init(){
        self::$var = new A();
    }
    B::init();
    

    【讨论】:

    • Andreas Niedermair:这就是 php 的工作方式(app-cycle= 单个请求)但是单例(在请求中的一个)是 php 中的一种可能性(在 php 中,单例是一个对象有 1 个实例(在应用周期内)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 1970-01-01
    • 1970-01-01
    • 2012-04-26
    • 2017-03-23
    • 1970-01-01
    • 2012-07-05
    相关资源
    最近更新 更多