web-dev-qa-db-ja.com

PHPクラスにコードを含めることはできますか?

PHPクラス、Myclass.phpとしましょう。このクラス内で、クラス自体といくつかのインスタンス変数のみを定義します。しかし、すべてのメソッドはMyclass_methodsから取得する必要があります。 phpファイル。そのファイルをクラス本体に含めることはできますか?

これを分離したいのには十分な理由があります。要するに、クラスのビジネスロジックを変更できるバックエンドがありますが、他のすべてのものはそのままにしておく必要があります。システムは、すべてのORMおよびその他のものを管理してくれます。

ただし、これが悪い考えである場合は、ビジネスロジック(この場合はユーザー定義のメソッド)を編集した後、クラスファイル全体を再生成することをお勧めします。

パフォーマンスの質問:1つのリクエスト中にMyclass.phpが一度だけ含まれる場合、実際にはそのMyclass_methods.phpも一度だけ含まれるべきです。間違っているかもしれません。専門家?

54
openfrog

いいえクラス本体にファイルを含めることはできません。
クラスを定義するファイルでは、メソッド本体または外部にのみファイルを含めることができますクラス本体

あなたの説明から、私はあなたがこれが欲しいと思う:

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

このようにすると、インクルードファイルの内容がクラススコープではなくメソッドスコープにインポートされます。インクルードファイルに関数と変数を含めることはできますが、メソッドを含めることはできません。あなたもできましたが、そうすべきではありませんスクリプト全体も入れて、メソッドの動作を変更します。

<?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が従わなければならない契約、つまりニャーメソッドを取得しました。次に、Mewing Behaviorを定義します。

<?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インターフェースを実装することを確認します。別のMeowing Behaviorを定義しましょう:

<?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およびmeowメソッドを定義し、それから具体的なRegularCatおよびLolkatクラスを導出することで上記を解決することもできますが、何を検討する必要があります達成する。あなたの猫が鳴く方法を決して変えないなら、先に進み、継承を使用しますが、RegularCatとLolkatが任意の鳴き声をすることができると思われる場合は、Strategyパターンを使用します。

PHPの詳細 デザインパターン については、次のリソースを確認してください。

166
Gordon

関連する基本機能を備えたコアクラスを作成し、必要なメソッドを使用してこれを拡張することは、アイデアではないかもしれません-より論理的なアプローチのように思えます。

8
John Parker

まず、メソッドを含む基本クラス、データを含むサブクラス、および動的クラスのロードを使用してこの問題を解決するのが最善ではない理由をあまり明確にしないことから始めます。正当な理由があると思います。

プロバイダーが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()関数を定義してそれらを選択することにより、これをさらに簡潔にすることができます。私が言ったように、この同じ問題は、継承を使用することでよりよく解決できます。ただし、多重継承タイプの問題がある場合、たとえば、3種類の髪型を持つ5種類の色を持つ4種類のペットがあり、60の異なるクラスごとに異なる方法の組み合わせが必要な場合、これは正しい解決策です。

5.4は現在リリース候補版(2012年2月24日現在)であり、リリースされてもほとんどのホストは何ヶ月もサポートしません。それまでは、完全に別個の完全なクラスファイルを記述する必要があります。ただし、特性を最終的に変更することを念頭に置いてクラスをフォーマットできます。

現時点では、マジックメソッドを使用して必要なものを部分的に取得し、利用可能な場合は特性に簡単にアップグレードできます。

コードファイル:

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()などのマジックメソッドを提供できないという点で制限があります。特性は、これらの制限の両方を解決します。

6
ldrut

これに特性を使用するのはどうですか?それは受け入れられる選択肢でしょうか?これは私が現在試しているもので、かなりうまくいくようです。

私がやっていることの簡単なバージョンは、基本的にこのようなものです。共有コアファイルと複数のプロジェクトを持つアプリケーションがあります。それらのプロジェクト内には、モジュールがあります。コアレベルのプロジェクト全体で使用できる機能を持ちたいが、その特定のプロジェクトでのみ使用したい。

私のプロジェクトコントローラー

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

古い質問を復活させるが、これはかなり簡単な解決策です。クラス専用の共通関数呼び出しが必要ですか?そうでない場合は、クラスと同じスコープ内に共通の関数ファイルを含めるだけです。クラスにメソッドを作成する必要がありますが、共通の関数を呼び出すだけで済みます。簡単な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
Chris Ohmstede

同じソフトウェアの無料版とプレミアム版を管理している場合、あなたが説明していることをしなければなりませんでした。 @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);
    }
0
Scott C Wilson

PHP5.4リリース以降、次のように動的オブジェクトを作成できます:- https://github.com/ptrofimov/jslikeobject

しかし、これはほとんどないベストプラクティスです。

0

私は最近これに出会い、解決策を思い付きました。それは私の場合に役立ちました。クラスには多くの関数が必要でしたが、クラスが肥大化したため、読みやすくするためにクラス関数をグループに分けたいと思いました。達成するには少し時間がかかりましたが、クラスの関数は$ thisに(あまり)依存していないため、クラス関数から "$ this"を削除し、それらの関数を含めるためのヘルパーファイルをいくつか作成しました。それにもかかわらず、$ thisが必要な場合、$ thisを関数に渡し、必要に応じてpublic set/get関数を追加することで、関数をヘルパーファイルに移動できました。それはハックですが、誰かを助けることは確実です

`class myClass {var x;

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

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

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

`

に対処することができます

`class 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など.

おそらくすべての場合において最良のルートではありませんが、私を大いに助けてくれました。基本的に、クラス関数は構築および委任するだけであり、計算はヘルパーに入れられました。

0
naglma