В 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');