Can OOP programming be emulated with just normal functions? Like with using static variables and anonymous functions: 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 vs Procedural Code。它解释了编写面向对象的代码(即使只有函数)。
此外,您应该意识到函数式编程是一种完全不同的开发范式。有针对这种范式的函数式语言:JavaScript、Scala、Haskell、Erlang。
我认为我能很快想到的最接近的方法是编写所有函数以将它们的第一个参数作为要操作的数据结构。可以这样想:
OOP 本质上只是将已知的数据结构与适当的行为相结合。
因此,如果您愿意相信自己只传递函数知道如何使用的数据结构,您可以对它进行程序化建模,每个“类”在全局空间中有两个数组,一个用于“实例”,一个用于“函数”(字面意思是可调用的数组,以它们的名称为键)。
我写了一些代码,将“类”定义为本质上是方法的集合,这些方法基本上可以$self
按照他们想要的方式处理(只要他们都知道会发生什么)。这是一个非常酷的想法(感谢您的提问!)。请注意匿名函数的使用,理论上,可以将其聚合为函数原型数组并用于许多不同的类(即,只有一个“描述”或“__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() 在子类未实现继承方法时查找继承的方法。这很有趣。请注意,只有最后两行实际上是“应用程序代码”……其余的相当于声明性“设置”代码(类似于类定义)和“运行时”函数。
OOP 是关于拥有一个初始化对象的构造函数,其他函数可以使用this
关键字“静态”访问。
所以是的,您可以在不使用诸如“class”、“this”或 __construct 之类的语言结构的情况下进行 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() 路线,您可以将填充函数作为属性存储在对象中,但您永远不会有$this
引用(不将其作为参数传递)或原型或任何其他类型的继承。你最好坚持使用 PHP 中的 class 关键字,没有理由绕过它。
如果您还需要继承,这就是它变得丑陋的地方:您需要创建重命名的函数以进行覆盖,为$self
数组/对象创建“类型”转换函数等。
可以办到。如果您有复杂的需求(如继承),它可能会变得非常难看。如果你有真正简单的需求,不那么丑陋,甚至可能有优势。
是的。例如,也许,在函数式语言中重载一个函数在某种程度上等同于 OOP 中的继承。但关键是,你甚至不应该考虑让用函数式语言编写的代码看起来像 OOP。将它们视为不同的工具,以实现相同的目标。
从理论上讲, OOP促进了更清洁的代码库,并且据说可以更轻松地重用代码。当它出现时,围绕这些概念进行了很多炒作,今天很多人甚至会说这是过度炒作。函数式语言在过去几年重新获得了应有的尊重,许多人已经意识到 OOP 只是一个 BUZZ 词,绝不是代码质量的保证。
函数式编程有许多编码技术和方法可以使它像 OOP 一样优雅。为工作使用正确的工具是任何项目的良好开端,正确使用它是您应该关注的主要部分。试图使特定项目的代码库看起来像使用函数式语言的 OOP 不会带来任何好处,并且必然会让某人感到痛苦:如果不是你,那就是必须维护它的人。
您的主要目标之一是拥有一个尽可能易于理解的代码库,并且有许多特定于函数式编程的方法可以处理这个问题,就像 OOP 中的方法一样。在我(非常谦虚的)看来,函数式编程甚至有一个优势,因为它更灵活。
我见过并管理过相当大的项目,这些项目让我很高兴。还有一些小的 OOP 项目,你很难理解。即使使用了正确的工具,在错误的人手中也会带来不好的结果。
我的 2 美分,快乐编码!
很多人对 OOP 到底是什么有不同的看法……我认为 OOP 是一种以非常具体的方式设计程序的方法,使用对象作为程序或计算的系统隐喻,可以帮助你灌输你的结果过程和软件具有许多非常好的、有用和强大的品质。
考虑到这一点,您可以在使用任何语言时应用 OOP 方法,在某些语言中比在其他语言中更容易做到这一点......通常在“OOP”语言中最简单,而这些语言不是强迫你的语言编写 OOP 代码(因为这是不可能的),但这为您提供了一组功能,如果您想遵循 OOP 方法,将使您的生活更轻松......
最后,要“模拟 OOP”足够好,最困难的“事情”是使用“行为”或“代码”作为数据的能力......这可以通过很多方式实现,比如 lambda 函数,或者一流的函数,或函数指针等......大多数现代语言至少支持其中一个。