【问题标题】:Right way to instantiate class in PHP在 PHP 中实例化类的正确方法
【发布时间】:2023-04-03 17:15:01
【问题描述】:

我正在尝试在类中创建一个方法,该方法将实例化当前所在的类。但我还需要该方法中的该方法才能在所有扩展类中正常工作。正如我从this thread 中了解到的,在此任务中使用self 关键字并不好。所以显而易见的选择是使用 static 关键字。

但是,我遇到了同样有效的不同方法。

例子:

class SimpleClass
{
    private $arg;

    public function __construct( $arg ){
        $this->arg = $arg;
    }

    public function getArg(){return $this->arg;}
    public function setArg($arg){$this->arg = $arg;}

    public function staticInstance()
    {
        return new static( $this->arg );
    }

    public function thisInstance()
    {
        return new $this( $this->arg );
    }

    public function selfInstance()
    {
        return new self( $this->arg );
    }
}

class ExtendedClass extends SimpleClass
{
}

$c1 = 'SimpleClass';
$c2 = 'ExtendedClass';

$inst1 = new $c1('simple');
$inst2 = new $c2('extended');

$static_instance_1 = $inst1->staticInstance();
$this_instance_1 = $inst1->thisInstance();
$self_instance_1 = $inst1->selfInstance();

$static_instance_2 = $inst2->staticInstance();
$this_instance_2 = $inst2->thisInstance();
$self_instance_2 = $inst2->selfInstance();

echo "SimpleClass Instances\n";
echo get_class($static_instance_1);
echo get_class($this_instance_1);
echo get_class($self_instance_1);

echo "ExtendedClass Instances\n";
echo get_class($static_instance_2);
echo get_class($this_instance_2);
echo get_class($self_instance_2);

从这个例子中我可以看到,staticInstancethisInstance 都产生“正确”的结果。还是他们?

谁能解释这两种方法之间的区别,哪一种是“正确”的。

【问题讨论】:

  • 不确定,但是,只要您使用new,就没有区别。使用 clone 并将实例存储在自身中时,这变得很有趣。
  • 我对静态与自我的了解是,如果您要从扩展类的对象实例调用它继承的方法,例如,创建一个new static ... ,它将创建扩展类的新实例。如果它使用了self,它将创建一个新的父实例(因为该方法存在于父中)
  • 关于静态和自我困境的一切都在我在问题的第一段中引用的链接中进行了解释。我的困境是在 $this 和 static 之间 :)

标签: php instance instantiation


【解决方案1】:

php.net 说:

从 PHP 5.3.0 开始,PHP 实现了一种称为后期静态绑定的功能,可用于在静态继承的上下文中引用被调用的类。

更准确地说,后期静态绑定通过存储在最后一个“非转发调用”中命名的类来工作。在静态方法调用的情况下,这是明确命名的类(通常是 :: 运算符左侧的类);在非静态方法调用的情况下,它是对象的类。 “转发调用”是由 self::、parent::、static:: 引入的静态调用,或者,如果在类层次结构中向上,则为 forward_static_call()。函数 get_call_class() 可用于检索带有被调用类名称的字符串,并且 static:: 引入其范围。

考虑到内部观点,此功能被命名为“后期静态绑定”。 “后期绑定”来自这样一个事实,即 static:: 不会使用定义方法的类来解析,而是使用运行时信息来计算。它也被称为“静态绑定”,因为它可以用于(但不限于)静态方法调用。

自我的局限:

对当前类的静态引用,如 self:: 或 CLASS 使用函数所属的类解析,如定义它的位置:

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        self::who();
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

上面的例子会输出:A

后期静态绑定的用法:

后期静态绑定试图通过引入一个关键字来解决这个限制,该关键字引用最初在运行时调用的类。基本上,一个关键字可以让您在前面的示例中从 test() 引用 B。决定不引入新关键字,而是使用已经保留的 static。

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

上面的例子会输出:B

$this 关键字是指当前对象,您不能在静态方法中使用它。当您说return $this 时,这意味着某些方法返回调用它的相同对象。

所以正确的方法是使用 static 关键字,因为如果你说 return new static() 它指的是方法当前所在的类。

【讨论】:

  • 我喜欢你的回答,因为它解决了我在魔法常数方面遇到的另一个问题:D
  • 有没有办法在不重新定义函数的情况下获取类名? (B类中没有额外的代码行)
  • 您也可以为此使用 php 反射 API。像这样:$reflB = new ReflectionClass('B'); echo $reflB-&gt;name; 所以你会得到类名
猜你喜欢
  • 1970-01-01
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 2014-12-13
相关资源
最近更新 更多