普通函数可以模拟OOP吗?

时间:2012-07-14 00:00:16

标签: php functional-programming

可以使用普通函数模拟OOP编程吗?与使用静态变量和匿名函数一样:http://php.net/manual/en/functions.anonymous.php

6 个答案:

答案 0 :(得分:2)

静态变量用于编写过程代码,乍一看看起来像OOP。

OOP是一种设计模式,与您使用的语言方面无关。阅读以下文章后,您将从中受益匪浅:OOP vs Procedural Code。它解释了编写面向对象的代码(即使只有函数)。

此外,您应该知道functional programming是一个完全不同的开发范例。有这种范例的功能语言:JavaScript,Scala,Haskell,Erlang。

答案 1 :(得分:2)

我认为我能想象到的最接近的就是编写所有函数,将第一个参数作为数据结构进行操作。可以这样想:

OOP本质上只是将已知的数据结构与适当的行为耦合在一起。

因此,如果您愿意相信自己只传递函数知道如何使用的数据结构,您可以在程序上对其进行建模,每个“类”在全局空间中有两个数组,一个用于“实例”,一个用于“函数”(字面意思是一系列可调用的密钥,以他们的名字命名)。

我编写了一些代码,它们将“类”定义为基本上是方法的集合,而这些方法基本上可以处理$self但是他们想要(只要他们都知道会发生什么)。这是一个非常酷的主意(感谢您的提问!)。注意匿名函数的使用,理论上可以将它们聚合到一个函数原型数组中,并在许多不同的类上使用(即只有一个“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 :(得分:2)

是。当你到达底层时,“对象只是函数的记录”,这在编程语言理论中是众所周知的。也就是说,如果你的语言具有类似记录的功能和适当的第一类功能(即“闭包”),那么“类”只是一个返回这种记录的函数。例如,在一些伪语法中(因为我的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

注意所有“方法”如何只是关闭局部变量(因此隐藏)的第一类函数。

如果你还想要继承,那么编码会更多地涉及,但仍然可以。

答案 3 :(得分:1)

是。例如,可能用功能语言重载函数在某种程度上等同于OOP中的继承。但关键是,你甚至不应该认为试图使用函数式语言编写的代码看起来像OOP。将它们视为不同的工具,以实现相同的目标。

OOP 理论上促进了更清晰的代码库,所谓的允许更容易地重用代码。 当它出现时,围绕着这些概念进行了大量宣传,许多人甚至会说今天这种概念过于夸张。功能语言在过去几年中重新获得了应有的尊重,许多人已经意识到OOP只是一个BUZZ词,绝不是代码质量的保证。

有许多编程技术和方法可以使函数编程与OOP一样优雅。对于任何项目来说,使用正确的工具是一个良好的开端,正确使用它是您应该注意的主要部分。试图使一个特定项目的代码库看起来像一个功能语言的OOP不会带来任何好处,并且必然会使某些人感到悲惨:如果不是你,那么必须维护它的人。

您的主要目标之一是让代码库尽可能易于理解,并且有许多特定于函数式编程的方法可以解决这个问题,就像OOP中的方法一样。在我(非常谦虚)的观点中,函数式编程甚至具有优势,因为它更灵活。

我已经看到并管理过相当大的项目,很高兴能够参与其中。还有一些小型的OOP项目非常难以理解。即使使用正确的工具,在错误的手中也会带来不好的结果。

我的2美分,快乐的编码!

答案 4 :(得分:1)

很多人对OOP到底是什么有不同的看法...... 我认为OOP是一种以非常特定的方式设计程序的方法,使用对象作为程序或计算的系统隐喻,它可以帮助您为最终的过程和软件灌输许多非常好,有用和强大的特性。

考虑到这一点,您可以在使用任何语言时应用OOP方法,使用某种语言比使用其他语言更容易...通常最简单的是“OOP”语言,而不是语言这会迫使你编写OOP代码(因为这是不可能的),但这会给你一系列功能,如果你想遵循OOP方法,那将会让你的生活更轻松......

最后,你需要“模拟OOP”的最困难的“事情”就是能够使用“行为”或“代码”作为数据......这可以通过很多方式实现,比如lambda函数,或第一类函数,或函数指针等......大多数现代语言至少支持其中一种。

答案 5 :(得分:1)

OOP是关于有一个构造函数,它启动一个对象,使用this关键字“静态地”访问其他函数。

所以是的,你可以在不使用“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类型会更好,也许能够使用 - > gt访问者,或利用引用自动传递):

function Something_constructor(&$self){
    $self=array(
        "member_var"=>"x",
    );
}

function fill(&$self, $strValue){
    $self["member_var"]=$strValue;
}

Something_constructor($arrInstance);

fill($arrInstance, "abc");

使用PHP&gt; = 5.3新的匿名函数功能,您可以在$ self数组/对象中添加成员函数作为属性,因为您可以直接调用($self["fill"]("abcde"))。如果为$ self使用对象数据类型,则可以使用更好的访问者。

根据你设计代码的方式,这个程序风格的OOP可能会被调整为在简单的RPC场景中很好地工作(但是,构造函数永远不会返回一个可用的$ self对象/数组,所以你也可以去完整的OOP和有同样的问题)。

如果进入(object)array()路由,你可以将fill函数作为属性存储在对象中,但是你永远不会有$this引用(不传递它作为param)或原型或任何其他类型的继承。你最好坚持使用PHP中的class关键字,没有理由去解决它。

如果你还需要继承,这就是丑陋的地方:你需要创建重命名的函数来覆盖$self数组/对象的“类型”转换函数等。

可以做到。如果您有复杂的需求(如继承),它可能会变得非常难看。如果你有非常简单的需求,不是那么难看,甚至可能有优势。