我想创建一个PHP类,比方说Myclass.php.现在在该类中我想要定义类本身和一些实例变量.但是所有方法都必须来自Myclass_methods.php文件.我可以将该文件包含在类体中吗?
我有很好的理由为什么我要分开这个.简而言之,我将有一个后端,我可以在其中更改类的业务逻辑,而所有其他事情必须保持不变.系统为我维护所有ORM和其他东西.
但是如果这是一个坏主意,那么在编辑业务逻辑之后重新生成整个类文件可能会更好(因此,在这种情况下是用户定义的方法).
性能问题:如果在一个请求中只包含一次Myclass.php,实际上Myclass_methods.php也应该只被包含一次.可能是错的.专家?
Gor*_*don 168
不可以.您不能在课程正文中包含文件.
在定义类的文件中,您只能在方法体中或类体外部包含文件.
从你的描述中我带你想要这个:
<?php // MyClass.php
class MyClass
{
protected $_prop;
include 'myclass-methods.php';
}
<?php // myclass-methods.php
public function myMethod()
{
$this->$_prop = 1;
}
Run Code Online (Sandbox Code Playgroud)
运行此代码将导致
Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION
Run Code Online (Sandbox Code Playgroud)
虽然这是可能的
<?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;
}
Run Code Online (Sandbox Code Playgroud)
这样做会将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';
Run Code Online (Sandbox Code Playgroud)
但是,以这种方式修补类以表现出不同的行为并不是你应该如何在OOP中完成它.这是完全错误的,应该让你的眼睛流血.
由于您希望动态更改行为,因此扩展类也不是一个好选择(请参阅下面的原因).你真正想要做的是编写一个接口,让你的类使用实现这个接口的对象,从而确保适当的方法可用.这称为战略模式,其工作方式如下:
<?php // Meowing.php
interface Meowing
{
public function meow();
}
Run Code Online (Sandbox Code Playgroud)
现在你得到了所有Meowing Behaviors必须遵守的合同,即采用喵喵方法.接下来定义一个Meowing行为:
<?php // RegularMeow.php
class RegularMeow implements Meowing
{
public function meow()
{
return 'meow';
}
}
Run Code Online (Sandbox Code Playgroud)
现在使用它,使用:
<?php // Cat.php
class Cat
{
protected $_meowing;
public function setMeowing(Meowing $meowing)
{
$this->_meowing = $meowing;
}
public function meow()
{
$this->_meowing->meow()
}
}
Run Code Online (Sandbox Code Playgroud)
通过将Meowing TypeHint添加到setMeowing,可以确保传递的param实现了Meowing接口.让我们定义另一种喵喵行为:
<?php // LolkatMeow.php
class LolkatMeow implements Meowing
{
public function meow()
{
return 'lolz xD';
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以轻松地交换这样的行为:
<?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';
Run Code Online (Sandbox Code Playgroud)
虽然你也可以通过定义一个抽象的 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();
Run Code Online (Sandbox Code Playgroud)
文件cat.php
trait PetSounds {
function speak() { echo 'meow'; }
}
Run Code Online (Sandbox Code Playgroud)
文件dog.php
trait PetSounds {
function speak() { echo 'woof'; }
}
Run Code Online (Sandbox Code Playgroud)
您可以通过将两个包含文件命名为相同,将它们放在不同的子目录中,并使用set_include_path()或定义__autoload()函数来在它们之间进行选择,从而使其更加清晰.就像我说的那样,使用继承可以更好地解决同样的问题.如果您有多重继承类型问题,例如,如果您有四种宠物,五种颜色和三种头发类型,并且您需要为60个不同类别中的每一种提供不同的方法组合,这是正确的解决方案.
5.4目前只是一个候选版本(截至2012年2月24日),甚至一旦发布,大多数主机将不会支持它好几个月 - 我们发布5.3版本之前需要18个月才能支持它.在此之前,您必须编写完全独立且完整的类文件.但是,您可以根据特征的最终更改来设置类的格式.
现在,您可以使用魔术方法部分获得所需内容,并在可用时轻松升级到特征.
代码文件:
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();
Run Code Online (Sandbox Code Playgroud)
文件cat.php
function TraitFunc_speak(Pet $that) { echo 'meow'; }
Run Code Online (Sandbox Code Playgroud)
文件dog.php
function TraitFunc_speak(Pet $that) { echo 'woof'; }
Run Code Online (Sandbox Code Playgroud)
但是您受到限制,因为您的函数无法访问私有和受保护的类属性和方法,并且您无法使用此方法来提供诸如__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(){
}
}
Run Code Online (Sandbox Code Playgroud)
扩展文件
trait Extensions{
// project-specific extensions
function this_project_only(){
echo 'Project Only';
}
}
Run Code Online (Sandbox Code Playgroud)
项目中的模块文件
class MyModule extends Modules{ // modules extends projects in a different class not relevant here
function do_something(){
echo $this->project_only();
}
}
Run Code Online (Sandbox Code Playgroud)