2010-03-31 3 views
15

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

У меня есть класс A и при создании экземпляра его передается файл, а в конструкторе класса A открывается файл.

Теперь в классе A есть функция, которую мне нужно вызвать, но мне не требуется передавать файл, и поэтому нет необходимости использовать конструкторскую функцию открытия файла, поскольку я не передаю файл.

Итак, мой вопрос: возможно ли любым способом создать экземпляр класса PHP без вызова его конструктора?

Note Я не могу сделать функцию static, поскольку я использую некоторые свойства класса в функции.

ответ

12

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

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

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

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

+1

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

+0

+1 для хороших альтернативных решений. – Yacoby

2

это не было бы лучше, чтобы сделать функцию, которую нужно static - изменить класс А так, что у него есть еще один конструктор, который не принимает никакого aruguments


Если класс имеет функцию, которая Безразлично 't получить доступ к любым нестационарным свойствам или функциям в классе, он может быть сделан статическим.

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->, вы не можете сделать его статическим.

+0

бы очень признательны, если вы можете подробнее рассказать это, как я не понимаю. – Rachel

+0

Теперь в чем разница, вызывая 'A-> foo() vs A :: foo()' – Rachel

+1

@Rachel: Вы бы назвали '$ a-> foo()' как метод экземпляра и 'A :: foo() 'как метод статического класса.Последнее не ** работает ** на экземплярах класса 'A', и поэтому вам не нужно вызывать' new A() 'для его создания. Чтобы получить лучшую идею, вы можете прочитать эту статью: http://en.wikipedia.org/wiki/Static_methods и документ PHP: http://www.php.net/manual/en/language.oop5.static .php –

-1

вы можете сделать метод статическим и вызвать его из контекста класса, а не из контекста объекта.

в коде будет выглядеть следующим образом:

class A { 
    public static function func($txt) { 
    print($txt); 
    } 
} 

A::func('test'); 
+0

Хм, как это может быть сделано, я действительно не уверен. Был бы признателен, если бы вы могли дать более подробное объяснение. – Rachel

13

Примечание: Решение ниже для PHP 5.3 и ниже. Начиная с PHP 5.4, вы также можете использовать do it via Reflection as shown elsewhere on this page.

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

Измененный PHPUnit_Framework_MockObject_Generator

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

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


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

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

echo serialize(new StdClass) // gives O:8:"stdClass":0:{} 

O означает объект. 8 - длина строки имени класса. "stdClass" - это, очевидно, название класса. Сериализованный объект имеет 0 набор свойств (подробнее к этому позже), обозначенный пустыми фигурными фигурными скобками. : - это просто разделители.

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

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

'O:7:"MyClass":0:{}' 

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

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

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

+0

Это очень трудно понять. Можете ли вы добавить к нему какое-то объяснение. – Rachel

+1

Этот код вручную создает сериализованное представление класса, а затем неэтериализует его. Это создает новую копию объекта без вызова конструктора. Однако он попытается вызвать метод __wakeup(). – Charles

+0

@ Rachel @Charles проделал хорошую работу, подытожив его уже, но также вижу мое подробное объяснение. – Gordon

17

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

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

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

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

+0

Спасибо за информацию. Документация PHP обманула меня ... –