2009-12-24 115 views
47

我想創建一個PHP類,讓我們說Myclass.php。現在在這個類中,我只想定義類本身和一些實例變量。但所有的方法都必須來自Myclass_methods.php文件。我可以只將該文件包含到類體中嗎?我可以將代碼包含到PHP類中嗎?

我有很好的理由爲什麼我要分開這個。簡而言之,我將擁有一個後端,可以在其中更改類的業務邏輯,而其他所有事情都必須保持不變。系統爲我維護所有的ORM和其他東西。

但是,如果這是一個壞主意,在編輯業務邏輯(在這種情況下用戶定義的方法)之後重新生成整個類文件可能會更好。

性能問題:如果在一個請求中只包含Myclass.php一次,實際上Myclass_methods.php應該只包含一次。可能是錯的。專家?

+10

不這樣做,學會正確使用OOP。 – 2009-12-24 11:39:01

+0

使用命名空間! – zloctb 2013-09-28 17:39:09

回答

153

不可以。您不能在類體中包含文件。
在定義類的文件中,您只能包含方法體以外的類體中的文件。

從你的描述我把你想這樣的:

<?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文件的內容導入方法範圍,而不是類範圍。您可以在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(); 
} 

你現在明白了所有的喵喵叫聲行爲必須服從,即有喵方法合同。接下來定義喵喵叫的行爲:

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

通過添加喵喵叫TypeHint到setMeowing,您確保傳遞PARAM實現喵喵叫聲接口。讓我們來定義另一喵喵叫的行爲:

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

雖然你也可能通過定義abstract BaseCat和喵方法,然後解決了以上inheritance從中得到具體的RegularCat和Lolkat類,你必須考慮你想要達到的目標。如果你的貓永遠不會改變他們的喵喵聲,繼續使用繼承,但是如果你的RegularCat和Lolkat應該能夠執行任意的meows,那麼就使用策略模式。說我不是太

+4

貓和喵喵的方法做到了。我會嘗試狗和樹皮的方法,但我意識到這將是一個完整的混亂。 – 2015-05-25 07:46:07

+0

**已淘汰!你可以包含文件!! **見:\t http://stackoverflow.com/a/47951483/2377343 – 2017-12-23 09:57:20

+0

@ T.Todua使用特徵是一個非常不同的東西,這裏問什麼,所以不,答案仍然存在並沒有過時。 – Gordon 2018-01-08 11:48:17

8

可能用相關的基本功能創建核心類並不是一個想法,然後用所需的方法擴展它 - 這似乎是一個更合理的方法。

+0

也調用源a.php中的類A到b.php中的類B的函數將比include_once()更好。像Pimpl成語。 – 2009-12-24 10:26:10

+0

你說得對,這很有道理。沒有想過這個選擇。 – openfrog 2009-12-24 10:26:33

6

我將開始:

對於PHP更design patterns,檢查這些資源明白爲什麼這個問題不是最好的解決使用包含方法的基類,包含數據的子類和動態類加載。我會假設你有一個很好的理由。

一旦你的提供者支持PHP 5.4,你可以使用traits來做你想要的。

代碼文件:

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

你在你的函數不能訪問私有然而限制和保護類屬性和方法,並且不能使用此方法提供諸如__g之類的魔術方法等()。性狀將解決這兩個限制。

+0

該死的很好的答案。 – Teson 2012-11-29 13:11:24

3

對此使用特質怎麼樣?這會是一個可以接受的選擇嗎?這是我目前正在試驗的事情,而且似乎很有用。

我正在做的簡化版本基本上就是這樣。我有一個共享核心文件和多個項目的應用程序。在這些項目中,我有模塊。我希望在覈心級別上具有可用於整個項目的功能,但僅限於該特定項目。

我的項目控制器

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

?> 
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); 
    } 
相關問題