Можно ли включить код в класс PHP?

Я хочу создать класс PHP, скажем Myclass.php. Теперь внутри этого класса я хочу определить только сам класс и некоторые переменные экземпляра. Но все методы должны поступать из файла Myclass_methods.php. Могу ли я просто включить этот файл в тело класса?

У меня есть веские причины, по которым я хочу отделить это. Короче говоря, у меня будет бэкэнд, в котором я могу изменить бизнес-логику класса, в то время как все остальное должно оставаться нетронутым. Система поддерживает все ORM и другие вещи для меня.

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

Вопрос о производительности: если во время одного запроса Myclass.php включен только один раз, на самом деле Myclass_methods.php также должен быть включен только один раз. Может быть, неправильно. Эксперты?

Нет. Вы не можете включать файлы в тело класса.
В файле, определяющем класс, вы можете включать только файлы в тело метода или вне тела класса .

Из вашего описания я хочу, чтобы вы этого хотели:

<?php // MyClass.php class MyClass { protected $_prop; include 'myclass-methods.php'; } <?php // myclass-methods.php public function myMethod() { $this->$_prop = 1; } 

Запуск этого кода приведет к

 Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION 

Что возможно, хотя это

 <?php // MyClass.php class MyClass { protected $_prop; public function __construct() // or any other method { include 'some-functions.php'; foo($b); // echoes 'a'; } } <?php // some-functions.php $b = 'a'; function foo($str) { echo $str; } 

Выполнение этого способа импортирует содержимое include-файла в область метода, а не в область класса. Вы можете включать функции и переменные во включенный файл, но не методы. Вы могли бы не включать все сценарии в него и изменять то, что делает этот метод, например

 <?php // MyClass.php // ... public function __construct($someCondition) { // No No Code here include ($someCondition === 'whatever') ? 'whatever.php' : 'default.php'; } // ... <?php // whatever.php echo 'whatever'; <?php // default.php echo 'foo'; 

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

Поскольку вы хотите динамически изменять поведение, расширение класса также не является хорошим вариантом (см. Ниже почему). То, что вы действительно хотите сделать, это написать интерфейс и сделать ваш класс использующим объекты, реализующие этот интерфейс, таким образом, чтобы убедиться, что соответствующие методы доступны. Это называется шаблоном стратегии и работает следующим образом:

 <?php // Meowing.php interface Meowing { public function meow(); } 

Теперь у вас есть контракт, согласно которому все Поведение Мяу должно подчиняться, а именно, иметь метод мяука. Затем определите поведение мяуканья:

 <?php // RegularMeow.php class RegularMeow implements Meowing { public function meow() { return 'meow'; } } 

Теперь, чтобы использовать его, используйте:

 <?php // Cat.php class Cat { protected $_meowing; public function setMeowing(Meowing $meowing) { $this->_meowing = $meowing; } public function meow() { $this->_meowing->meow() } } 

Добавляя параметр Meowing TypeHint для setMeowing, вы убедитесь, что прошедший параметр реализует интерфейс Meowing. Давайте определим другое поведение по методу:

 <?php // LolkatMeow.php class LolkatMeow implements Meowing { public function meow() { return 'lolz xD'; } } 

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

 <?php require_once 'Meowing.php'; require_once 'RegularMeow.php'; require_once 'LolkatMeow.php'; require_once 'Cat.php'; $cat = new Cat; $cat->setMeowing(new RegularMeow); echo $cat->meow; // outputs 'meow'; // now to change the behavior $cat->setMeowing(new LolkatMeow); echo $cat->meow; // outputs 'lolz xD'; 

Хотя вы также могли бы решить вышеизложенное с наследованием , определив абстрактный метод BaseCat и meow, а затем выведя из него конкретные классы RegularCat и Lolkat, вы должны подумать о том, чего вы хотите достичь. Если ваши кошки никогда не изменят способ мяука, продолжайте использовать наследование, но если ваш RegularCat и Lolkat должны будут делать произвольные мяки, используйте шаблон стратегии.

Для получения дополнительных шаблонов проектирования в PHP проверьте эти ресурсы:

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

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

Как только ваш провайдер поддерживает PHP 5.4, вы можете делать то, что хотите, используя черты.

Файл кода:

 if ($pet === 'dog') include 'dog.php'; elseif ($pet === 'cat') include 'cat.php'; else die('Unknown pet'); class Pet { use PetSounds; } $myPet = new Pet(); $myPet->speak(); 

Файл cat.php

 trait PetSounds { function speak() { echo 'meow'; } } 

Файл dog.php

 trait PetSounds { function speak() { echo 'woof'; } } 

Вы можете сделать это еще более чистым, назвав оба файла include одинаковыми, поместив их в разные подкаталоги и используя set_include_path () или определяя функцию __autoload (), чтобы выбрать между ними. Как я уже сказал, эта же проблема может быть решена лучше, используя наследование. Если у вас проблема с множественным наследованием, хотя, например, у вас есть четыре вида домашних животных с пятью видами цветов с тремя типами волос, и вам нужно различное сочетание методов для каждого из 60 разных классов, это правильное решение ,

5.4 в настоящее время является только кандидатом на выпуск (по состоянию на 2/24/2012), и даже когда-то выпущенный большинство хостов не будет поддерживать его в течение многих месяцев – моя работала через 18 месяцев после выпуска 5.3, прежде чем они ее поддержали. До тех пор вы должны писать полностью отдельные и полные файлы классов. Тем не менее, вы можете отформатировать свои классы с возможным изменением характеристик.

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

Файл кода:

 if ($pet === 'dog') include 'dog.php'; elseif ($pet === 'cat') include 'cat.php'; else die('Unknown pet'); class Pet { public function __call($name, array $arguments) { array_unshift($arguments, $this); return call_user_func_array("TraitFunc_$name", $arguments); } } $myPet = new Pet(); $myPet->speak(); 

Файл cat.php

 function TraitFunc_speak(Pet $that) { echo 'meow'; } 

Файл dog.php

 function TraitFunc_speak(Pet $that) { echo 'woof'; } 

Однако вы ограничены тем, что ваши функции не могут получить доступ к закрытым и защищенным свойствам и методам класса, и вы не можете использовать этот метод для предоставления магических методов, таких как __get (). Черты будут решать обе эти ограничения.

Как насчет использования черт для этого? Будет ли это приемлемым вариантом? Это то, с чем я в настоящее время экспериментирую, и, похоже, работает довольно долго.

Упрощенная версия того, что я делаю, в основном такая. У меня есть приложение с общими файлами ядра и несколькими проектами. В рамках этих проектов у меня есть модули. Я хочу иметь функции, доступные для всего проекта на базовом уровне, но только для этого конкретного проекта.

Мой контроллер проекта

 if(is_file(PROJECT_PATH.'/project_extensions.trait.php')){ // additional functions for this specific project require_once(PROJECT_PATH.'/project_extensions.trait.php'); }else{ // no additional functions trait Extensions{}; } Class Project{ USE Extensions; // default functions shared between all projects function shared_stuff(){ } } 

Файл расширений

 trait Extensions{ // project-specific extensions function this_project_only(){ echo 'Project Only'; } } 

Файл модуля в проекте

 class MyModule extends Modules{ // modules extends projects in a different class not relevant here function do_something(){ echo $this->project_only(); } } 

Могу ли я просто включить этот файл в тело класса?

Нет.

Начиная с версии PHP5.4 вы можете создавать динамические объекты, подобные этому: https://github.com/ptrofimov/jslikeobject

Но это вряд ли лучшая практика.

Возрождение старого вопроса, но это довольно простое решение. Вам нужны, чтобы общие вызовы функций были эксклюзивными для вашего класса? Если нет, просто укажите свой общий файл (ы) функции в той же области, что и ваш класс. Вам нужно будет создавать методы в своем классе, но им нужно будет только вызвать общую функцию. Вот простой пример SOAP-сервера:

 <?php include 'post_function.php'; $server = new SoapServer( null, array('uri' => "http://localhost/") ); $server->setClass( 'postsoapclass' ); $server->handle(); class postsoapclass { public function animalNoise( $animal ) { return get_animal_noise($animal); } } ?> 

post_function.php

 <?php function get_animal_noise($animal) { if(strtolower(trim($animal)) == 'pig') { return 'Oink'; } else { return 'This animal is mute'; } } ?> 

Я должен был делать то, что вы описываете, в тех случаях, когда я поддерживаю бесплатную версию и премиальную версию того же программного обеспечения. Потому что, как заметил @Gordon, вы не можете сделать именно это:

 class SomeClass { premium_file = "premium.php"; if (file_exists($premium_file)) { require($premium_file); } 

Вместо этого я делаю это:

  premium_file = "premium.php"; if (file_exists($premium_file)) { require($premium_file); } class SomeClass { ... 

Для функций, которые вы хотите ссылаться, создайте методы класса в основном классе и вызовите метод включенного файла, передав $this указатель $this в качестве параметра. Чтобы я мог сразу понять, где находятся функции, я буду префикс имени включенных функций, как показано ниже:

  class SomeClass { ... // Premium functions public function showlist() { premium_showlist($this); } 

ВОЗМОЖНО !

(используя trait с php 5.4)

your_file.php

 include "additional_file.php"; class YourClass{ use additional_methods; public function My1() {} public function My2() {} } 

additional_file.php:

 trait additional_methods{ public function My3() {} public function My4() {} } 

(спасибо @user за ответ)