В PHP можно создать экземпляр класса без вызова класса конструктора?
Каким-либо образом, возможно ли создать экземпляр класса php без вызова его конструктора?
У меня есть класс A и при создании экземпляра его передается файл, а в конструкторе класса A открывается файл.
Теперь в классе A есть функция, которую мне нужно вызвать, но мне не требуется передавать файл, и поэтому нет необходимости использовать конструкторскую функцию открытия файла, поскольку я не передаю файл.
Итак, мой вопрос: возможно ли каким-либо образом создать экземпляр класса PHP без вызова его конструктора?
Примечание Я не могу сделать функцию static, поскольку я использую некоторые свойства класса в функции.
Ответы
Ответ 1
Конструктор классов всегда будет вызываться. Есть несколько способов, которыми вы могли бы обойти это.
Первый способ - предоставить значения по умолчанию для ваших параметров в конструкторе и выполнять только определенные действия по этим параметрам, если они установлены. Например:
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
}
}
Ответ 2
В вашем случае я бы рекомендовал подумать о перепроектировании вашего кода, чтобы вам не нужно было делать такие вещи, но чтобы ответить на ваш вопрос: да, возможно.
Вы можете использовать ReflectionClass, а метод newInstanceWithoutConstructor представлен в PHP 5.4. Тогда очень просто создать экземпляр класса без вызова его конструктора:
$reflection = new ReflectionClass("ClassName");
$instance = $reflection->newInstanceWithoutConstructor(); //That it!
Ответ 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. Но если вы должны иметь такой код в своем производственном коде, вы, вероятно, будете делать что-то очень странное.
Поскольку вы попросили объяснение:
Когда вы сериализуете объект, вы получаете строковое представление объекта. Например,
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 является
'O:7:"MyClass":0:{}'
Вы заменили бы оба вхождения "MyClass" в строке 4 вашим желаемым именем класса, чтобы создать сериализованную строку класса, который вы хотите создать, без вызова контроллера.
Эта строка затем не инициализируется в экземпляр MyClass в строке 1, минуя конструктор. Неэтериализованный экземпляр будет иметь все методы этого класса, а также любые свойства. Если в MyClass есть свойства, они будут иметь значения по умолчанию, если вы не добавите разные значения в сериализованную фиктивную строку.
И это уже оно. Ничего слишком волшебного в этом.
Ответ 4
Не было бы лучше сделать нужную функцию static
- измените класс A так, чтобы он имел другой конструктор, который не принимает никаких побочных эффектов
Если класс имеет функцию, которая не имеет доступа к каким-либо не статическим свойствам или функциям в классе, она может быть сделана статической.
class A{
public function __construct($arg1){
}
public static function foo(){
//do something that doesn't involve the class properties
}
}
Затем его можно вызывать без необходимости создания класса
//the constructor will not be called as we haven't created an instance of A
A::foo();
Разница между статической и не статической функцией заключается в том, что статическая функция не может получить доступ к свойствам класса функций, которые также являются статическими. Так что если в foo()
у вас есть код, который использует $this->
, вы не можете сделать его статическим.
Ответ 5
вы можете сделать метод статическим и вызвать его из контекста класса, а не из контекста объекта.
в коде он будет выглядеть так:
class A {
public static function func($txt) {
print($txt);
}
}
A::func('test');