我可以包含代码到PHP类吗?
我想做一个PHP类,让我们说Myclass.php。 现在在这个类里面我只想定义类本身和一些实例variables。 但是所有的方法都必须来自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文件中包含函数和variables,但不包括方法。 你可以但不应该把整个脚本也放进去,并改变方法的作用,例如
<?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';
但是,以这种方式修补类来展现不同的行为不是你应该如何在OOP中完成的。 这只是错误的,应该让你的眼睛stream血。
既然你想dynamic地改变行为,扩展类也不是一个好的select(见下文为什么)。 你真正想要做的是写一个接口,并让你的类使用实现这个接口的对象,从而确保适当的方法是可用的。 这就是所谓的战略模式 ,像这样工作:
<?php // Meowing.php interface Meowing { public function meow(); }
现在你得到了所有Meowing Behaviors必须服从的合同,即有一个喵喵的方法。 接下来定义一个Meowing行为:
<?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接口。 我们来定义另一个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类,你必须考虑你想实现什么。 如果你的猫永远不会改变他们喵喵的方式,继续使用inheritance,但如果你的RegularCat和Lolkat应该能够做任意的喵,那么使用策略模式。
有关PHP中的更多devise模式 ,请查看以下资源:
用相关的基本function创build核心类并不是一个好主意,然后用所需的方法扩展它 – 这看起来更合乎逻辑。
我将首先说我不太清楚为什么使用包含方法,包含数据的子类和dynamic类加载的基类不能最好地解决这个问题。 我会假设你有一个很好的理由。
一旦你的提供者支持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'; } }
通过命名两个包含文件相同,将它们放在不同的子目录中,并使用set_include_path()或定义一个__autoload()函数在它们之间进行select,可以使它更清晰。 就像我说的那样,使用inheritance可以更好地解决同样的问题。 如果你有一个多inheritancetypes的问题,例如,如果你有四种types的宠物,五种颜色,三种头发types,你需要60个不同类别的不同方法的组合,这是正确的解决scheme。
5.4目前只是发布候选版本(截至2012年2月24日),甚至一旦发布,大多数主机都不会支持它好几个月 – 我发布了5.3个发布之后的18个月才支持它。 在此之前,您必须编写完全独立且完整的类文件。 然而,你可以devise你的课程,最终改变你的特质。
现在,你可以使用魔法方法部分得到你想要的东西,并在有可用的情况下轻松升级到特征。
代码文件:
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'; }
然而,你的function是有限的,因为你的函数不能访问私有和受保护的类属性和方法,你不能使用这个方法来提供诸如__get()之类的魔术方法。 性状将解决这两个限制。
那么使用这个特性呢? 这是一个可以接受的select吗? 这是我目前正在试验的东西,它似乎工作很长一段时间。
我正在做的简化版本基本上是这样的。 我有一个共享核心文件和多个项目的应用程序。 在这些项目中,我有模块。 我想要在核心层面上为整个项目提供可用的function,但仅限于该特定项目。
我的项目控制器
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发布以来,您可以创build如下所示的dynamic对象 : https : //github.com/ptrofimov/jslikeobject
但这几乎不是最好的做法。
振兴一个老问题,但这是一个相当简单的解决scheme。 你需要通用的函数调用来排除你的类吗? 如果没有,只需将您的通用函数文件包含在与您的课程相同的范围内即可。 你将需要在你的类中创build方法,但他们只需要调用通用函数。 这是一个简单的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 { ...
对于要引用的函数,在主类中创build类方法,并调用包含文件的方法,将$this
指针作为parameter passing。 所以我可以一目了然地告诉函数在哪里,我将前缀所包含函数的名称如下所示:
class SomeClass { ... // Premium functions public function showlist() { premium_showlist($this); }