OOPプログラミングは通常の機能だけでエミュレートできますか?静的変数と無名関数を使用する場合と同様に:http://php.net/manual/en/functions.anonymous.php
6 に答える
はい。その根底にあるのは、プログラミング言語理論でよく知られている「オブジェクトは単なる関数の記録」です。つまり、レコードのような機能と適切なファーストクラス関数(つまり「クロージャ」)を備えた言語がある場合、「クラス」は単にそのようなレコードを返す関数です。たとえば、いくつかの疑似構文では(私のPHPは初歩的であるため):
func Point(x, y) {
var my_x = x
var my_y = y
var this = {
getX : func() { return my_x }
getY : func() { return my_y }
move : func(dx, dy) { my_x += dx; my_y += dy }
dist : func() { return sqrt(this.getX()**2 + this.getY()**2) }
}
return this
}
var p = Point(0, 3)
p.move(2, -5)
p.getY() // -2
すべての「メソッド」が、ローカル変数(したがって非表示になっている)を閉じるファーストクラスの関数であることに注意してください。
継承も必要な場合は、エンコーディングがより複雑になりますが、それでも可能です。
静的変数は、一見OOPのように見える手続き型コードを記述するために使用されます。
OOPはデザインパターンであり、使用する言語の側面とは関係ありません。次の記事を読むことで多くのメリットが得られます:OOPと手続き型コード。オブジェクト指向コードを書くために説明します(関数だけでも)。
また、関数型プログラミングはまったく異なる開発パラダイムであることに注意する必要があります。このパラダイムのために作られた関数型言語があります:JavaScript、Scala、Haskell、Erlang。
私がすぐに想像できる最も近いのは、操作するデータ構造として最初の引数を取るようにすべての関数を作成することだと思います。このように考えてください:
OOPは基本的に、既知のデータ構造と適切な動作を結合するだけです。
したがって、関数が操作方法を知っているデータ構造のみを渡すことを信頼する場合は、各「クラス」がグローバル空間に2つの配列(1つは「インスタンス」用、もう1つは「インスタンス」用)を持つように、手続き的にモデル化できます。 「関数」(文字通り、名前をキーにした呼び出し可能オブジェクトの配列)。
私は「クラス」を本質的にメソッドのコレクションとして定義するいくつかのコードを書きました、そしてそれらのメソッドは本質的に彼らが望むように扱うことができます$self
(彼ら全員が何を期待するかを知っている限り)。これはかなりクールなアイデアです(質問してくれてありがとう!)。理論的には、関数プロトタイプ配列に集約され、多くの異なるクラスで使用できる無名関数の使用に注意してください(つまり、1つの「description」または「__ toString」クラスがすべてのクラスで機能します)。
編集:作業コード:
<?php
// The "Runtime" //
function makeObject($class, $constructorArgs) {
global $classes;
$constructorArgs = (array) $constructorArgs;
$instance = $classes[$class]['instances'][] = array();
$instance['_class'] = $class;
$instance = callMethod($instance, 'construct', $constructorArgs);
return $instance;
}
function callMethod($instance, $method, $args = array()) {
global $classes;
return call_user_func_array($classes[$instance['_class']]['methods'][$method], array_merge(array($instance), $args));
}
// Class definition for "Person" //
$classes['Person'] = array();
$classes['Person']['methods'] = array();
$classes['Person']['methods']['construct'] = function($self, $name) {
$self['name'] = $name;
return $self;
};
$classes['Person']['methods']['sayHello'] = function($self)
{
echo "hello, my name is " . $self['name'] . "\n";
};
$classes['Person']['instances'] = array();
// Begin "Application" code.
// equivalent to:
// $person = new Person("sally");
// $person->sayHello();
$person = makeObject('Person', "sally");
callMethod($person, "sayHello");
これは明らかに、楽しく興味深い方法で拡張できます。たとえば、「メソッド」関数の構造を作り直して$ parent引数を取り、子クラスが親を呼び出せるようにし、子が実装していないときにcallMethod()が継承されたメソッドを検索できるようにすることができます。これはとても楽しいです。最後の2行だけが実際には「アプリケーションコード」であることに注意してください...残りは宣言型の「セットアップ」コード(クラス定義に類似)および「ランタイム」関数と同等です。
this
OOPは、オブジェクトを開始するコンストラクター関数を持ち、キーワードを使用して「静的に」他の関数にアクセスできるようにすることです。
そうです、「class」、「this」、__constructなどの言語構造を使用せずにOOPを実行できます。
通常のOOP:
class Something{
public $member_var;
public function __construct(){
$this->member_var="x";
}
public function fill($strValue){
$this->member_var=$strValue;
}
}
$objInstance=new Something();
$objInstance->fill("abc");
手続き型言語構造を使用したOOP(Objectクラスを避けてOOPのものから遠ざけましたが、$ self型に使用するか、->アクセサーを使用できるようにするか、自動を利用する方がよいでしょう。参照渡し):
function Something_constructor(&$self){
$self=array(
"member_var"=>"x",
);
}
function fill(&$self, $strValue){
$self["member_var"]=$strValue;
}
Something_constructor($arrInstance);
fill($arrInstance, "abc");
PHP> = 5.3の新しい無名関数機能を使用すると、メンバー関数を$ self配列/オブジェクト内のプロパティとして追加できます。これは、直接呼び出すことができるためです($self["fill"]("abcde")
)。$ selfにオブジェクトデータ型を使用すると、より優れたアクセサーが可能になります。
コードの設計方法によっては、この手続き型OOPは、単純なRPCシナリオでうまく機能するように調整される場合があります(ただし、コンストラクターは使用可能な$ selfオブジェクト/配列を返すことはないため、完全なOOPを実行して同じものを使用することをお勧めします。問題)。
(object)array()ルートを使用する場合は、fill関数をプロパティとしてオブジェクトに格納できますが、$this
参照(paramとして渡さずに)、プロトタイプ、またはその他の種類の継承はありません。PHPのclassキーワードに固執する方がよいでしょう、それを回避する理由はありません。
継承も必要な場合は、これが醜いところです。オーバーライドする名前の変更された関数、$self
配列/オブジェクトの「型」変換関数などを作成する必要があります。
それはできます。複雑なニーズ(継承など)がある場合は、本当に醜くなる可能性があります。本当に単純なニーズがあり、それほど醜いものではない場合は、おそらく利点があります。
はい。たとえば、関数型言語で関数をオーバーロードすることは、たとえばOOPでの継承とある程度同等です。しかし、要点は、関数型言語で書かれたコードをOOPに見せようとすることさえ考えるべきではないということです。同じ目標を達成するために、それらを異なるツールと考えてください。
理論上、 OOPはよりクリーンなコードベースを促進し、おそらくコードをより簡単に再利用できるようにします。それが出たとき、これらの概念の周りに多くの誇大宣伝がありました、多くは今日それが誇大宣伝であったとさえ言うでしょう。関数型言語は、過去数年間にふさわしい尊敬を取り戻しました。多くの人々は、OOPは単なる流行語であり、コードの品質を保証するものではないことに気づきました。
関数型プログラミングには、OOPと同じくらいエレガントにすることができる多くのコーディング手法とアプローチがあります。仕事に適したツールを使用することは、どのプロジェクトにとっても良いスタートです。それを適切に使用することは、注意を払うべき主要な部分です。特定のプロジェクトのコードベースを関数型言語でOOPのように見せようとしても、何のメリットももたらさず、将来的に誰かを惨めにすることになります。あなたでなければ、それを維持しなければならない人です。
主な目標の1つは、コードベースをできるだけ理解しやすくすることです。OOPのアプローチと同様に、これを処理する関数型プログラミングに固有のアプローチが多数あります。私の(非常に謙虚な)意見では、関数型プログラミングはより柔軟であるため、利点さえあります。
私は、非常に大規模なプロジェクトを見て、管理することができました。そして、頭を包み込むのが非常に難しいいくつかの小さなOOPプロジェクトもありました。適切なツールを使用しても、悪意のある人が悪い結果をもたらす可能性があります。
私の2セント、幸せなコーディング!
多くの人がOOPとは何かについて異なる意見を持っています...OOPは、プログラムまたは計算のシステムメタファーとしてオブジェクトを使用して、非常に特殊な方法でプログラムを設計する方法論であり、結果を吹き込むのに役立ちます。非常に素晴らしく、便利で強力な品質を備えたプロセスとソフトウェア。
そのことを念頭に置いて、任意の言語を使用しながらOOP方法論を適用できます。一部の言語では、他の言語よりもはるかに簡単です...一般的に、強制する言語ではない「OOP」言語で最も簡単です。 OOPコードを書くために(それは不可能であるため)、しかしそれはあなたに一連の機能を与えます、あなたがOOP方法論に従いたいならば、あなたの人生を楽にするでしょう...
最後に、「OOPをエミュレート」するために必要な最も難しい「もの」は、データとして「動作」または「コード」を使用する機能です...これは、ラムダ関数やファーストクラス関数、または関数ポインターなど...現代の言語のほとんどは、それらの少なくとも1つをサポートしています。