Есть ли способ предотвратить создание объекта внутри его конструктора, чтобы:
$object = new Foo(); echo $object; // outputs: NULL
Нет, это невозможно; new
ключевое слово всегда возвращает экземпляр указанного класса, независимо от того, что вы пытаетесь вернуть из конструктора. Это связано с тем, что к моменту создания вашего конструктора PHP уже завершил выделение памяти для нового объекта. Другими словами, объект уже существует в этой точке (в противном случае нет объекта, для которого вообще можно вызвать конструктор).
Вы могли бы поднимать ошибки или вызывать исключения из конструктора вместо этого и обрабатывать их соответственно.
class Foo { public function __construct() { throw new Exception('Could not finish constructing'); } } try { $object = new Foo(); } catch (Exception $e) { echo $e->getMessage(); }
Невозможно, но вы можете проксимизировать создание .
<?php class Foo { private function __construct() {} static function factory($create=False) { if ($create) { return new Foo; } } }
Просто бросьте исключение:
throw new Exception('thou shalt not be born!');
Вы можете реализовать фабрику для создания объекта для вас. Если вы используете PHP 5.3.0+, тогда у вас будет доступ к функции под названием Late Static Binding, которая упростит это.
<?php class MyObject { protected $loadSuccess = false; protected function __construct ($foo, $bar, $baz) { // Just a random 50/50 success probability. Put real logic for testing success here $this -> loadSuccess = (mt_rand (0, 99) > 49); } static public function factory ($foo, $bar, $baz) { $objClass = get_called_class (); $obj = new $objClass ($foo, $bar, $baz); if ($obj -> loadSuccess) { return ($obj); } } } class MySubClass extends MyObject { protected function __construct ($foo, $bar, $baz) { parent::__construct ($foo, $bar, $baz); if ($this -> loadSuccess) { echo ('Hello, I\'ma ' . get_called_class () . '<br>'); } } } class MySubSubClass extends MySubClass { protected function __construct ($foo, $bar, $baz) { parent::__construct ($foo, $bar, $baz); if ($this -> loadSuccess) { echo ($foo * $bar * $baz . '<br>'); } } } $o1 = MyObject::factory (1, 2, 3); // Base class $o2 = MySubClass::factory (4, 5, 6); // Child class $o3 = MySubSubClass::factory(7, 8, 9); // Descendent class var_dump ($o1); var_dump ($o2); var_dump ($o3); ?>
Если вы используете версию PHP до 5.3.0, тогда ситуация становится немного более сложной, поскольку поздняя статическая привязка и get_called_class () недоступны. Однако PHP 5 поддерживает отражение, и вы можете использовать его для эмуляции позднего статического привязки. В качестве альтернативы вы можете реализовать отдельный заводский класс и передать ему аргумент, указывающий, какой объект вы хотите инициализировать.
Другой подход заключается в том, чтобы заставить ваш конструктор генерировать исключение, если он терпит неудачу, и обработать его блоком catch. Однако этот метод может получить волосатый вид, если вы делаете это много, и его следует использовать только тогда, когда вы обычно ожидаете, что создание объекта будет успешным (другими словами, если сбой создания является исключительным обстоятельством).
Фабричный подход имеет дополнительные преимущества, например, он может содержать кэш объектов, которые вы уже создали, и если вы попытаетесь создать один и тот же объект дважды, он просто передаст вам ссылку на уже инициализированный объект вместо создания нового , Это устраняет проблемы с памятью и обработкой, присущие созданию объекта, особенно если создание включает в себя трудоемкую задачу, такую как сложный SQL-запрос
Если вы пытаетесь остановить объект от создания экземпляра в зависимости от нескольких условий, то почему бы не создать условие, прежде чем вы даже попадете в new
PHP и создадите экземпляр класса?
Я имею в виду, скажем, в вашем примере:
$object = new Foo(); echo $object; // outputs: NULL
Вы можете обернуть его в функцию, которая выполняет валидацию для вас или просто оператор if, если вы только собираетесь создать экземпляр класса один раз.
Как это:
if(conditions_to_meet){ $object = new Foo(); } else $object = NULL;
если вам нужно создать несколько экземпляров, а затем обернуть их в функцию и передать параметры вашему классу.
Надеюсь это поможет.