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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1957732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 04:26:33  来源:igfitidea点击:

Can I include code into a PHP class?

phpoopclass

提问by openfrog

I want to make a PHP class, lets say Myclass.php. Now inside that class I want to define just the class itself and some instance variables. But all the methods must come from a Myclass_methods.php file. Can I just include that file into the class body?

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

I have good reasons why I want to seperate this. In short, I'll have a backend in which I can change the business logic of a class, while all other things must remain untouched. The system maintains all the ORM and other stuff for me.

我有充分的理由想把它分开。简而言之,我将有一个后端,我可以在其中更改类的业务逻辑,而所有其他事情必须保持不变。系统为我维护所有的 ORM 和其他东西。

But if this is a bad idea, it might be better to re-generate the whole class file after editing the business logic (so, the user-defined methods in this case).

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

Performance question: If during one request Myclass.php is included just once, actually that Myclass_methods.php should also be included just once. Might be wrong. Experts?

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

回答by Gordon

No. You cannot include files in the class body.
In a file defining a class, you may only include files in a method bodyor outside the class body.

不可以。您不能在类主体中包含文件。
在定义类的文件中,您只能在方法体中类体之外包含文件。

From your description I take you want this:

根据你的描述,我认为你想要这个:

<?php // MyClass.php
class MyClass
{
    protected $_prop;
    include 'myclass-methods.php';
}

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

Running this code will result in

运行此代码将导致

Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION

What is possible though is this

不过这是可能的

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

Doing it this way, will import the contents of the include file into the method scope, not the class scope. You may include functions and variables in the include file, but not methods. You could but should notput entire scripts into it as well and change what the method does, e.g.

这样做,会将包含文件的内容导入方法范围,而不是类范围。您可以在包含文件中包含函数和变量,但不能包含方法。您可以但不应该将整个脚本也放入其中并更改方法的作用,例如

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

However, patching the class this way to exhibit different behavior is not how you should do it in OOP. It's just plain wrong and should make your eyes bleed.

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

Since you want to dynamically change behavior, extending the class is also not a good option (see below why). What you really will want to do is write an interfaceand make your class use objects implementing this interface, thus making sure the appropriate methods are available. This is called a Strategy Patternand works like this:

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

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

Now you got the contract that all Meowing Behaviors must obey, namely having a meow method. Next define a Meowing Behavior:

现在你得到了所有喵喵行为都必须遵守的契约,即有一个喵喵方法。接下来定义喵喵行为:

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

Now to use it, use:

现在要使用它,请使用:

<?php // Cat.php
class Cat
{
    protected $_meowing;

    public function setMeowing(Meowing $meowing)
    {
        $this->_meowing = $meowing;
    }

    public function meow()
    {
        $this->_meowing->meow()
    }
}

By adding the Meowing TypeHintto setMeowing, you make sure that the passed param implements the Meowing interface. Let's define another Meowing Behavior:

通过将 Meowing TypeHint添加到 setMeowing,您可以确保传递的参数实现了 Meowing 接口。让我们定义另一个喵喵行为:

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

Now, you can easily interchange behaviors like this:

现在,您可以轻松地交换如下行为:

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

While you also could have solved the above with inheritanceby defining an abstractBaseCat and meow method and then deriving concrete RegularCat and Lolkat classes from that, you have to consider what you want to achieve. If your cats will never change the way they meow, go ahead and use inheritance, but if your RegularCat and Lolkat is supposed to be able to do arbitrary meows, then use the Strategy pattern.

虽然您也可以通过定义抽象BaseCat 和 meow 方法,然后从中派生出具体的 RegularCat 和 Lolkat 类,通过继承解决上述问题,但您必须考虑要实现的目标。如果您的猫永远不会改变它们喵喵叫的方式,请继续使用继承,但是如果您的 RegularCat 和 Lolkat 应该能够进行任意喵叫,那么请使用 Strategy 模式。

For more design patternsin PHP, check these resources:

有关PHP 中的更多设计模式,请查看以下资源:

回答by John Parker

Might it not be an idea to create the core class with the relevant base functionality and then extend this with the required methods - it seems like a more logical approach.

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

回答by ldrut

I'll start by saying I'm not too clear why this problem is not best solved using a base class containing the methods, subclasses containing the data, and dynamic class loading. I'll assume you have a good reason.

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

Once your provider supports PHP 5.4 you can do what you want using traits.

一旦您的提供者支持 PHP 5.4,您就可以使用特征做您想做的事情。

Code File:

代码文件:

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

File cat.php

文件 cat.php

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

File dog.php

文件狗.php

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

You could make this even cleaner by naming both include files the same, putting them in different subdirectories, and using set_include_path() or defining an __autoload() function to select between them. Like I said though, this same problem could be solved better using inheritance. If you have a multiple-inheritance type problem though, if for instance you have four kinds of pets with five kinds of colors with three hair types and you need a different combination of methods for each of the 60 different classes, this is the right solution.

您可以通过将两个包含文件命名相同,将它们放在不同的子目录中,并使用 set_include_path() 或定义 __autoload() 函数在它们之间进行选择来使这更加清晰。就像我说的,使用继承可以更好地解决同样的问题。如果你有一个多继承类型的问题,例如你有四种宠物,五种颜色,三种头发,你需要为 60 种不同的类中的每一种使用不同的方法组合,这是正确的解决方案.

5.4 is currently just a Release Candidate (as of 2/24/2012) and even once released most hosts will not support it for many months - mine took 18 months after 5.3 was released before they would support it. Until then you must write entirely separate and complete class files. You can however format your classes with an eventual change to traits in mind.

5.4 目前只是一个候选版本(截至 2012 年 2 月 24 日),即使一旦发布,大多数主机也不会支持它好几个月——我的在 5.3 发布后花了 18 个月才支持它。在此之前,您必须编写完全独立且完整的类文件。但是,您可以在考虑最终更改特征的情况下格式化您的类。

Right now you can partially get what you want using magic methods and have an easy upgrade to traits when they are available.

现在,您可以使用魔法方法部分获得您想要的东西,并在特征可用时轻松升级到特征。

Code File:

代码文件:

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

File cat.php

文件 cat.php

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

File dog.php

文件狗.php

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

You are limited however in that your functions can not access private and protected class properties and methods and you can not use this method to provide magic methods such as __get(). Traits will solve both of those limitations.

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

回答by Thomas Smart

What about using traits for this? Would that be an acceptable option? This is something I am currently experimenting with and it seems to work quite while.

为此使用特征怎么样?这是一个可以接受的选择吗?这是我目前正在试验的东西,它似乎工作了很长时间。

A simplified version of what I am doing is basically like this. I have an application with shared core files and multiple projects. Within those projects i have modules. I want to have functions that are available for the entire project on a core level but only for that specific project.

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

My project controller

我的项目控制器

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(){

  }
}

Extensions file

扩展文件

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

Module file in the project

项目中的模块文件

class MyModule extends Modules{ // modules extends projects in a different class not relevant here

  function do_something(){
    echo $this->project_only();
  }
}

回答by Chris Ohmstede

Reviving an old question but this is a fairly simple solution. Do you need the common function calls to be exclusive to your class? If not, simply include your common function file(s) within the same scope as your class. You will need to create methods in your class but they will only need to call the common function. Here's a simple SOAP server example:

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

post_function.php

<?php

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

?>

回答by Scott C Wilson

I have had to do what you are describing in cases where I maintain a free version and a premium version of the same software. Because, as @Gordon noted, you cannot do exactly this:

在我维护同一软件的免费版本和高级版本的情况下,我不得不执行您所描述的操作。因为,正如@Gordon 所指出的,你不能完全这样做:

class SomeClass {  

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

Instead I do this:

相反,我这样做:

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

  class SomeClass {
    ...

For functions you want to reference, create class methods in the main class, and call the included file's method, passing the $thispointer as a parameter. So that I can tell at a glance where functions are, I will prefix the name of the included functions as shown below:

对于要引用的函数,在主类中创建类方法,并调用包含文件的方法,将$this指针作为参数传递。为了让我一目了然地知道函数在哪里,我将在包含的函数的名称前面加上前缀,如下所示:

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

回答by naglma

I came across this recently, and came up with a solution, that helped in my case. I wanted many functions in a class, but the class became bloated, so wanted to separate out the class functions into groups for readability. It took a little time to accomplish, but since the functions of the class didn't rely (much) on $this, I removed "$this" from the class functions and created several helper files to include those functions. When $this was necessary, I could nevertheless move the function into a helper file, by passing $this to the function, adding public set/get functions where necessary. It's a hack, but it's sure to help someone

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

` class myClass { var x;

` class myClass { var x;

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

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

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

`

`

can be worked around to

可以解决

` class myClass { var x;

` class myClass { var x;

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

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

`

`

and helper function set 1

和辅助函数集 1

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

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

and helper function set 2, etc.

和辅助函数集 2 等。

Probably not the best route in all cases, but helped me out a lot. Basically the class functions were only to construct and delegate, and the calculations were put into helpers.

可能不是所有情况下的最佳路线,但对我帮助很大。基本上类函数只是构造和委托,计算被放入助手中。

回答by Renato Cuccinotto

Since PHP5.4release you can create dynamic objectslike this: https://github.com/ptrofimov/jslikeobject

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

But this is scarcelythe best practice.

但这几乎不是最佳实践。