PHP - 只能由另一个类实例化的类

7
假设有这样一个场景:
class Page {}

class Book {
   private $pages = array();
   public function __construct() {}
   public function addPage($pagename) {
      array_push($this->pages, new Page($pagename));
   }
}

有没有办法确保只有我的书类(Book)的对象可以实例化页面(Page)? 比如,如果程序员尝试这样做:

$page = new Page('pagename');

脚本抛出了异常吗?
谢谢。

1
为什么?那是不好的实践。 - Daniel A. White
1
这个实际上是关于 Python 的,但我认为它非常适用:"在这里我们都是自愿的成年人"。 - Gabi Purcaru
1
为什么这是一个不好的做法,@Daniel? - André Alçada Padez
4个回答

5

我明白您的观点,但使用该语言提供的工具是不可能做到的。

您可以在构造页面时要求传入一个书籍对象:

class Page {
    public function __construct( Book $Book ) {}
}

class Book {
    public function addPage() {
        $this->pages[] = new Page( $this );
    }
}

谢谢你的回答,它有点帮助了我。出于明显的原因,我将不得不接受@genesis的答案。 - André Alçada Padez
为什么?我告诉过你这是不可能的,同时提供了一个替代方案:P - Rijk

5

这可能有点牵强,但你可以使用以下方法:

abstract class BookPart
{
    abstract protected function __construct();
}

class Page
    extends BookPart
{
    private $title;

    // php allows you to override the signature of constructors
    protected function __construct( $title )
    {
        $this->title = $title;
    }
}

class Book
    extends BookPart
{
   private $pages = array();

   // php also allows you to override the visibility of constructors
   public function __construct()
   {
   }

   public function addPage( $pagename )
   {
      array_push( $this->pages, new Page( $pagename ) );
   }
}

$page = new Page( 'test will fail' ); // Will result in fatal error. Comment out to make scrip work 

$book = new Book();
$book->addPage( 'test will work' ); // Will work.

var_dump( $book );

是的,这有点牵强,但正好做到了我所要求的。非常感谢。 - André Alçada Padez
聪明!即使启用了,它甚至也不会引发 E_STRICT 级别的错误。 - Mchl

3

我认为你能够做到的最好方式,就是让Page在其构造函数参数中需要一个Book实例,并且让它将页面添加到该Book实例中。这样一来,你就不会有漂浮的Page了,但它们总是与某本书绑定在一起(尽管仍然可能在多本Book中出现相同的Page)。

class Book {
  public function addPage($page) {
    if(is_a($page,'Page') {
      $this->pages->push($page);
    } else if (is_string($page)) {
      new Page($this,$page)
    } else {
      throw new InvalidArgumentException("Expected string or 'Page' - ".gettype($page)." was given instead");
    }
  }
}

class Page {
  public function __construct(Book $book, $pagename) {
    $book->addPage($this);
  }
}

那看起来很丑... :/

1
不可能。在PHP中,这是不可能的。即使可能,开发人员也可以根据自己的需求进行修改并禁用你的异常...

1
当然,这是正确的,但是期望从你的类/接口中得到什么意义呢?我认为你通常希望其他开发人员不要触碰你的类库,如果他们想要使用它们,或者如果他们打算篡改它,就不会保证预期的结果。更重要的是;如果你发布了类库的更新,他们将不得不再次修改它们,一遍又一遍,无穷无尽。 - Decent Dabbler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接