我可以将代码包含到PHP类中吗?

时间:2009-12-24 10:19:47

标签: php oop class

我想创建一个PHP类,比方说Myclass.php。现在在该类中我想要定义类本身和一些实例变量。但是所有方法都必须来自Myclass_methods.php文件。我可以将该文件包含在类体中吗?

我有很好的理由为什么我要分开这个。简而言之,我将拥有一个后端,我可以在其中更改类的业务逻辑,而所有其他事情必须保持不变。系统会为我维护所有ORM和其他内容。

但是如果这是一个坏主意,那么在编辑业务逻辑之后重新生成整个类文件可能会更好(因此,在这种情况下是用户定义的方法)。

性能问题:如果在一个请求中只包含一次Myclass.php,实际上Myclass_methods.php也应该只被包含一次。可能是错的。专家?

9 个答案:

答案 0 :(得分:163)

否。您不能在课程正文中包含文件。
在定义课程的文件中,您只能在方法正文在课程正文之外包含文件。

根据你的描述我想要你:

<?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';

但是,以这种方式修补类以表现出不同的行为并不是你应该如何在OOP中完成它。这是完全错误的,应该让你的眼睛流血。

由于您希望动态更改行为,因此扩展类也不是一个好选择(请参阅下面的原因)。你真正想要做的是写一个interface并让你的类使用实现这个接口的对象,从而确保适当的方法可用。这称为Strategy Pattern,其工作方式如下:

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

现在你得到了所有Meowing Behaviors必须遵守的合同,即采用喵喵方法。接下来定义一个喵喵行为:

<?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,可以确保传递的param实现了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';

虽然您也可以通过定义inheritance BaseCat和meow方法,然后从中获取具体的RegularCat和Lolkat类来解决上述abstract,但您必须考虑要实现的目标。如果你的猫永远不会改变他们的喵喵方式,那就继续使用继承,但是如果你的RegularCat和Lolkat应该能够做任意的喵喵叫,那么就使用策略模式。

有关PHP中的更多design patterns,请查看以下资源:

答案 1 :(得分:8)

创建具有相关基本功能的核心类可能不是一个想法,然后使用所需的方法扩展它 - 这似乎是一种更合乎逻辑的方法。

答案 2 :(得分:6)

我首先要说的是,我不太清楚为什么使用包含方法的基类,包含数据的子类和动态类加载来最好地解决这个问题。我认为你有充分的理由。

一旦您的提供商支持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()函数来在它们之间进行选择,从而使其更加清晰。就像我说的那样,使用继承可以更好地解决同样的问题。如果您有多重继承类型问题,例如,如果您有四种宠物,五种颜色和三种头发类型,并且您需要为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();

文件cat.php

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

文件dog.php

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

但是您的功能有限,因为您的函数无法访问私有和受保护的类属性和方法,并且您无法使用此方法来提供诸如__get()之类的魔术方法。特征将解决这两个限制。

答案 3 :(得分:5)

为此使用特征怎么样?这是一个可以接受的选择吗?这是我目前正在尝试的东西,它似乎很有效。

我正在做的简化版本基本上就是这样。我有一个共享核心文件和多个项目的应用程序。在这些项目中,我有模块。我希望在核心级别上拥有可用于整个项目的功能,但仅适用于该特定项目。

我的项目控制器

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();
  }
}

答案 4 :(得分:0)

PHP5.4 版本发布以来,您可以像这样创建动态对象https://github.com/ptrofimov/jslikeobject

但这 是最佳做法。

答案 5 :(得分:0)

恢复旧问题,但这是一个相当简单的解决方案。您是否需要将常用函数调用专属于您的课程?如果没有,只需将您的公共函数文件包含在与您的类相同的范围内。您需要在类中创建方法,但它们只需要调用公共函数。这是一个简单的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';
    }
}

?>

答案 6 :(得分:0)

在我维护免费版本和同一软件的高级版本的情况下,我必须做你所描述的内容。因为正如@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指针作为参数传递。所以我可以一眼看出函数的位置,我将在所包含函数的名称前面加上如下所示:

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

答案 7 :(得分:0)

我最近遇到了这个问题,并提出了一个解决方案,这对我的情况很有帮助。我需要一个类中的许多函数,但该类变得肿,因此想将类函数分成几组以提高可读性。花了一些时间才能完成,但是由于该类的函数不(过多)依赖$ this,因此我从类函数中删除了“ $ this”,并创建了一些帮助文件来包含这些函数。当需要$ this时,我仍然可以通过将$ this传递给函数,并在必要时添加公共set / get函数,将函数移至帮助文件中。这是骇客,但一定可以帮助某人

`     类myClass     {         var x;

    function myClass()
    {
        $this->x = 0;
    }

    function myFunc1Group1()
    {
        $x = $this->x;
        $x++;
        $this->x = $x;
    }
    function myFunc2Group1(){}

    function myFunc1Group2(){}
    function myFunc2Group2(){}
}

`

可以解决

`     类myClass     {         var x;

    function myClass()
    {
        $this->x = 0;
    }

    function doSomething()
    {
        // not called on $this but takes $this as a parameter
        myFunc1Group1($this);
    }
}

`

和辅助功能设置1

function myFunc1Group1($THIS_OBJECT) { $x = $THIS_OBJECT->getX(); $x++; $THIS_OBJECT->setX($x); } function myFunc2Group1($THIS_OBJECT){}

和辅助功能集2,等等。

在所有情况下可能都不是最佳途径,但对我有很大帮助。基本上,类函数仅用于构造和委托,并将计算结果放入助手中。

答案 8 :(得分:0)

您可以在声明类之前包含或要求,如下所示:

require 'path-to-file';
class myClass{
  function show($uid){

  }
}