有没有办法阻止类实例化而不是从特定其他类的实例中实例化?

时间:2012-09-13 18:28:45

标签: php oop

我有两个类AB,都来自同一个父级。在PHP中,有没有办法确保除了B类之外的类A无法实例化?

(班级B不是A的孩子。)

3 个答案:

答案 0 :(得分:4)

使用debug_backtrace

class Ancestor{}

class A extends Ancestor{

    public function buildB()
    {

        return new B;

    }

}

class B extends Ancestor{

    public function __construct(){

        $backtrace = debug_backtrace();
        if( $backtrace[1]['class'] !== 'A' )
            throw new Exception("Don't you dare!");

        echo "Built successful!\n";

    }

}

试一试:

//Everything ok this way:
$a = new A;
$a -> buildB();

// You will have an exception in any other case:
try{

    $b = new B; 

}catch(Exception $e){

    echo $e -> getMessage();

}

编辑:如果您想确保在B的代码中创建A,您也可以这样做 - 只需将buildB设为私有^^。

答案 1 :(得分:1)

我不是从PHP的角度考虑这个问题,而是从oop方面考虑更多......想想你能实现它的唯一方法就是你将B的构造函数设为私有,然后公开一个接受A参数的静态方法然后该方法可以私有地实例化B并通过out参数将其返回给A.

//Pseudocode, language-indifferent

    class A{
       var _B;

       public B GetMeAnInstanceOfB(){
          _B=B.CreateInstanceOfB(this);
       }

       //alternate
       public B GetMeAnotherInstanceOfB(){
          _B=new B(this);
       }
    }

    class B{
       private B();
       //alternate
       private B(A);
       static B CreateInstanceOfB(A){
          return new(b);
       }
    }

那真的很粗糙,可能充满了坑洼,但是有一点刺痛。从技术上讲,A的子类仍然可以得到一个B,所以如果你密封了类(防止了子类),那就会关闭那扇门。

有趣的问题,确定......

编辑:这个mod真的不能解决问题,但也许(?)它更好 - 我为B创建了一个公共构造函数,它将A作为参数,并实例化B现在只发生在A中。唯一的问题是它坚持JDelage指出的同样问题 - 如果我实例化A,我可以建立一个B ......

答案 2 :(得分:1)

如何实现它是,让类B的构造函数接受一个参数。并为类A定义一个方法,该方法可以生成B的对象。

如果$argument == null ||,则死亡或抛出执行!($argument instanceof A)

示例代码:

class X {
    public $i = 0;
    public function getI() {
        return $i;
    }
    public function setI($x) {
        $i = $x;
    }
}

class A extends X {
    public function setI($x) {
        $i = $x * 2;
    }
    public function makeB($var){
        $b = new B($var);
    }
}

class B extends X {
    public function __construct($a) {
        if (null == $a) {
            echo "no arguments given!\r\n";
            //exit;
        }else if (!($a instanceof A)) {
            echo "disallowed\r\n";
            //exit;
        }else{
            echo "initialized b\r\n";
        }
    }
    public function setI($x) {
        $i = $x * 3;
    }
}

$a = new A();

$a->makeB();
$a->makeB(new X());
$a->makeB(&$a);

输出:

Warning: Missing argument 1 for A::makeB(), called in file.php
no arguments given!
disallowed
initialized b

您可以看到演示here