Php класс без конструктора

В PHP возможно ли создать экземпляр класса без вызова конструктора класса?

Каким-либо образом, возможно ли создать экземпляр класса php без вызова его конструктора? У меня есть класс A и при создании экземпляра его передается файл, а в конструкторе класса A открывается файл. Теперь в классе A есть функция, которую мне нужно вызвать, но мне не требуется передавать файл, и поэтому нет необходимости использовать конструкторскую функцию открытия файла, поскольку я не передаю файл. Итак, мой вопрос: возможно ли каким-либо образом создать экземпляр класса PHP без вызова его конструктора? Примечание Я не могу сделать функцию static, поскольку я использую некоторые свойства класса в функции.

5 ответов

Конструктор классов всегда будет вызываться. Есть несколько способов, которыми вы могли бы обойти это. Первый способ — предоставить значения по умолчанию для ваших параметров в конструкторе и выполнять только определенные действия по этим параметрам, если они установлены. Например:

class MyClass < public __construct($file = null) < if ($file) < // perform whatever actions need to be done when $file IS set >else < // perform whatever actions need to be done when $file IS NOT set >// perform whatever actions need to be done regardless of $file being set > > 

Другой вариант — расширить ваш класс таким образом, чтобы конструктор дочернего класса не вызывал конструктор родительского класса.

class MyParentClass < public __construct($file) < // perform whatever actions need to be done regardless of $file being set >> class MyChildClass extends MyParentClass < public __construct() < // perform whatever actions need to be done when $file IS NOT set >> 

Или, как уже отмечали другие, статический метод может лучше всего соответствовать вашим потребностям в зависимости от того, что вы пытаетесь сделать.

+1 за расширение класса. Может быть, это класс сторонней библиотеки, которая не должна быть изменена .

Хорошие решения, хотя я считаю, что параметр $file все еще должен существовать в классе расширений, иначе вы получите предупреждение с E_STRICT . Достаточно просто проигнорировать переменную внутри метода.

В вашем случае я бы рекомендовал подумать о перепроектировании вашего кода, чтобы вам не нужно было делать такие вещи, но чтобы ответить на ваш вопрос: да, возможно.

Вы можете использовать ReflectionClass, а метод newInstanceWithoutConstructor представлен в PHP 5.4. Тогда очень просто создать экземпляр класса без вызова его конструктора:

$reflection = new ReflectionClass("ClassName"); $instance = $reflection->newInstanceWithoutConstructor(); //That it! 

Ничего не стоит, что newInstanceWithoutConstructor() будет доступен с PHP 5.4.0. Он недоступен ни в одной версии PHP 5.3 или ниже.

Примечание. Решение ниже для PHP 5.3 и ниже. Начиная с PHP 5.4, вы также можете сделать это через Reflection, как показано в другом месте на этой странице.

Это действительно возможно.

Изменено от PHPUnit_Framework_MockObject_Generator

1 $myClass = unserialize( 2 sprintf( 3 'O:%d:"%s":0:<>', 4 strlen('MyClass'), 'MyClass' 5 ) 6 ); 

Пожалуйста, имейте в виду, что этот код, как и все, хорош и оправдан в рамках PHPUnit. Но если вы должны иметь такой код в своем производственном коде, вы, вероятно, будете делать что-то очень странное.

Читайте также:  Background html not repeat

Поскольку вы попросили объяснение:

Когда вы сериализуете объект, вы получаете строковое представление объекта. Например,

echo serialize(new StdClass) // gives O:8:"stdClass":0:<> 

Объект O означает объект. 8 — длина строки имени класса. «stdClass» — это, очевидно, имя класса. Сериализованный объект имеет 0 свойства set (подробнее об этом позже), обозначенные пустыми фигурными фигурными скобками. : являются просто разделителями.

Каждая сериализованная строка может быть воссоздана в свое исходное «живое» значение с помощью функции unserialize. Это позволит обойти конструктор. Подобно тому, как Чарльз правильно указал, что магический метод __wakeup() будет вызываться, если он определен (так же, как __sleep() будет вызываться при сериализации).

В строке 3 вы видите строку, подготовленную для использования с sprintf (строка 2). Как вы можете видеть, длина строки имени класса указывается как %d , а имя класса указывается как %s . Это означает, что sprintf должен использовать первый аргумент, переданный ему в строке 4, как цифру, а второй — как строку. Следовательно, результатом вызова sprintf является

Вы заменили бы оба вхождения «MyClass» в строке 4 вашим желаемым именем класса, чтобы создать сериализованную строку класса, который вы хотите создать, без вызова контроллера.

Эта строка затем не инициализируется в экземпляр MyClass в строке 1, минуя конструктор. Неэтериализованный экземпляр будет иметь все методы этого класса, а также любые свойства. Если в MyClass есть свойства, они будут иметь значения по умолчанию, если вы не добавите разные значения в сериализованную фиктивную строку.

И это уже оно. Ничего слишком волшебного в этом.

Источник

ReflectionClass::newInstanceWithoutConstructor

Создаёт новый экземпляр класса без вызова конструктора.

Список параметров

Возвращаемые значения

Ошибки

Если класс является встроенным, и его экземпляр не может быть создан без вызова конструктора, то это приведёт к генерации исключения ReflectionException . Это исключение ограничено только классами с модификатором final.

Смотрите также

  • ReflectionClass::newInstance() — Создаёт экземпляр класса с переданными аргументами
  • ReflectionClass::newInstanceArgs() — Создаёт экземпляр класса с переданными параметрами

User Contributed Notes 6 notes

It should be made clear that from an OOP theory perspective the use of this method is very bad practice in the same manner as goto, eval and singletons. If you find a need to use it in production code you’re almost certainly doing something wrong somewhere. It may occasionally be useful for debugging, but even then hints at poor initial code.

The problem? It breaks encapsulation. An object can exist in the application but may not be able to fulfill its responsibility because it’s missing dependencies. The use of this method makes it possible for an incomplete object to exist in the system; the object can exist in a state that its author never intended. This is bad because it will cause unexpected things to happen! A fundamental principle in OOP is that objects are in complete control of their state, the use of this method prevents that guarantee.

n.b. The annotation based «dependency injection» listed below is not a solution or valid use-case for this either because it breaks encapsulation (Among other things!) and the class being constructed needs to know of the container by providing annotations.

Читайте также:  Read excel table python

If this method is not available in your version of PHP you can use a trick to create an instance without calling the constructor.
Use reflection to get the properties and default values of the class, and create a fake «serialized» string.

function createInstanceWithoutConstructor ( $class ) $reflector = new ReflectionClass ( $class );
$properties = $reflector -> getProperties ();
$defaults = $reflector -> getDefaultProperties ();

$serealized = «O:» . strlen ( $class ) . «:\» $class \»:» . count ( $properties ) . ‘: foreach ( $properties as $property ) $name = $property -> getName ();
if( $property -> isProtected ()) $name = chr ( 0 ) . ‘*’ . chr ( 0 ) . $name ;
> elseif( $property -> isPrivate ()) $name = chr ( 0 ) . $class . chr ( 0 ). $name ;
>
$serealized .= serialize ( $name );
if( array_key_exists ( $property -> getName (), $defaults ) ) $serealized .= serialize ( $defaults [ $property -> getName ()]);
> else $serealized .= serialize ( null );
>
>
$serealized .= «>» ;
return unserialize ( $serealized );
>
?>

Example:

class foo
public $a = 10 ;
protected $b = 2 ;
private $c = «default» ;
protected $d ;
public function __construct () $this -> a = null ;
$this -> b = null ;
$this -> c = «constructed» ;
$this -> d = 42 ;
>
>

var_dump ( createInstanceWithoutConstructor ( ‘foo’ ));
?>

Output:
object(foo)#6 (4) [«a»]=>
int(10)
[«b»:protected]=>
int(2)
[«c»:»foo»:private]=>
string(7) «default»
[«d»:protected]=>
NULL
>

I hope this can help someone.
Oliver Anan

sorry for replying to such an old comment, but there’s something i wanted to point out.

@ tom at r dot je:
While I agree with what you said in general, there *are* cases where it’s not true, and since PHP doesn’t allow for multiple constructors there’s no other good way around it.

> The problem? It breaks encapsulation.
> An object can exist in the application but may not be able to fulfill its
> responsibility because it’s missing dependencies.
> The use of this method makes it possible for an incomplete object
> to exist in the system;
> the object can exist in a state that its author never intended.

If you’re using this method from some factory method, to manually init the object in other way that the constructor that, this point is no longer valid.

Consider the example, where you use constructor to set-up the object after getting it from database (e.g. you need to pull some array from other table, basing on some id parameter). But you want to also be able to create object manually (for inserting to the database, for example).
The best thing to do would be to have two different constructors, but since it is not possible in php you need some other way to create the object.

// this usually would be a static cache in some class, or array returned by method getMeta($id), etc.
$meta = array( 1337 => array( ‘key1’ => ‘value1’ , ‘key2’ => ‘value2’ ));

class Test public $id ;
public $data ;
public $meta ;

public function __construct () global $meta ;
if( is_int ( $this -> id )) $this -> meta = $meta [ $this -> id ];
>
public static function create_empty () $r = new ReflectionClass ( __CLASS__ );
return $r -> newInstanceWithoutConstructor ();
>
>
echo «emulating PDO::FETCH_CLASS behavior: » ;
$t = Test :: create_empty ();
$t -> meta = 1337 ;
$t -> __construct ();
var_dump ( $t );

Читайте также:  Python умножить матрицы numpy

echo «empty class: » ;
$testItem = Test :: create_empty ();
// . here you can start setting up the item, e.g. from XML
var_dump ( $testItem );

$testItem -> id = 0 ;
$testItem -> data = «some data» ;
$testItem -> meta = array( «somekey» => «somevalue» );

echo «after setup:» ;
var_dump ( $testItem );
?>

Of course, you can instead make empty constructor, and create some init() method, but then you have to remember to call init() everywhere.
You can also create some other way of adding the item to database, but then you’d have to classes to handle the same data — one for retrieving and other for storing.

If you instead use some factory class (or just a factory method, like in the simplified example above) having a way to create totally empty object is useful. With full factory approach you would first use some TestFactory->prepare() method, then you’d call methods to set what you need, and the factory would set all uninitialized variables to some default values upon calling TestFactory->get() to retrieve prepared object.

Источник

Создавать объект без вызова его конструктора в PHP

Чтобы восстановить состояние объекта, который был сохранен, я хотел бы создать пустой экземпляр класса без вызова его конструктора, чтобы позже установить свойства с помощью Reflection .

Единственный способ, которым я нашел, как это делает Doctrine , – создать поддельную сериализацию объекта и unserialize() :

function prototype($class) < $serialized = sprintf('O:%u:"%s":0:<>', strlen($class), $class); return unserialize($serialized); > 

Есть ли другой, менее хакерский способ сделать это?

Я ожидал найти такой способ в Reflection, но я этого не сделал.

Обновление: ReflectionClass :: newInstanceWithoutConstructor доступен с PHP 5.4!

Другой способ – создать дочерний элемент этого класса с и пустым конструктором

class Parent < protected $property; public function __construct($arg) < $this->property = $arg; > > class Child extends Parent < public function __construct() < //no parent::__construct($arg) call here >> 

а затем использовать тип Child:

$child = new Child(); //set properties with reflection for child and use it as a Parent type 

По определению, экземпляр объекта включает вызовы его конструктора. Вы уверены, что не хотите писать более легкие конструкторы? (И нет, я не думаю, что есть другой способ.)

Есть ли еще […] способ сделать это?

Нет. По крайней мере, не переопределяя кодовую базу класса, используя расширения, такие как runkit .

В PHP Reflection нет функции, которая позволит вам создать экземпляр нового объекта без вызова конструктора.

Это, безусловно, невозможно по двум причинам:

  1. Объекты либо сериализуются, либо нет.
  2. serialize / unserialize является самой естественной реализацией PHP настойчивости объекта вокруг

Все остальное будет означать больше работы, большей реализации и большего количества кода – поэтому, скорее всего, более хаки в ваших словах.

Источник

Оцените статью