为什么要在什么时候使用PHP面向对象编程而不是基本函数?

59

有一些关于这个问题的帖子,但我并没有清楚地理解何时使用面向对象编程,何时在include中使用程序化函数。有人也告诉我,OOP 运行起来很慢,会增加更多的工作量。这对吗?

假设我有一个包含50个函数的大文件。为什么我要用类来调用它们呢?而不是通过 function_name() 来调用它们?我应该转换并创建一个包含所有函数的对象吗?它的优势或具体区别是什么?在 PHP 中采用 OOP 编码有什么好处?模块化?


1
我之前写了一篇博客文章,或许可以帮助你理解它们之间的区别:面向过程编程与面向对象编程的解释 - VirtuosiMedia
VirtuosiMedia,死链接...? - Mike Wells
10个回答

44
在许多情况下,过程式编程就足够了。仅仅为了使用面向对象而使用它是没有意义的,特别是如果你最后只会得到POD对象(纯旧数据)。

面向对象的主要优势来自于继承和多态。如果你使用类,但从未使用这两个概念中的任何一个,那么你可能第一次使用类时不需要它。

我认为 OO 最好的地方之一是允许您摆脱基于类型切换的代码。请考虑:

function drive($the_car){

    switch($the_car){

      case 'ferrari':
          $all_cars->run_ferrari_code();
          break;

      case 'mazerati':
          $all_cars->run_mazerati_code();
          break;

      case 'bentley':
          $all_cars->run_bentley_code();
          break;
    }
}

使用其面向对象的替代方案:

function drive($the_car){

    $the_car->drive();
}

多态性将允许基于运行时信息发生适当类型的"驾驶"。


关于多态的注释:

这里的第二个例子有一些前提条件:即所有汽车类都将扩展一个抽象类或实现一个接口

两者都允许你强制扩展或实现类来定义特定的函数,例如drive()。这非常强大,因为它允许您drive()所有汽车,而无需知道您正在驾驶哪一种;这是因为它们扩展了包含drive()方法的抽象类或实现了强制定义drive()方法的接口。

因此,只要确保所有特定的汽车都扩展抽象类car或实现诸如canBeDriven之类的接口(两者都必须声明drive()方法),您就可以在对象上调用drive()方法,您知道它是一辆汽车(但不知道是什么类型的汽车),而不必担心未定义,因为PHP会向您抛出致命错误,直到您在特定的汽车类中定义这些方法。


10
我不太明白你提供的另一个例子是什么意思。 - Codex73
2
如果您使用适当的面向对象编程,那么$the_car可以指向任何类型的汽车。因为所有不同类型的汽车都有一个drive()方法,所以您可以安全地调用它,而不管汽车的类型如何。在运行时,它知道汽车的类型,并自动调用正确的方法。 - Majd Taby
10
刚刚看到这个,但是也没有理解替代示例。你只是将一个对象传递给函数并调用drive()。猜测您在实例化期间定义了对象,但没有显示出来?这作为面向对象编程(OOP)的示例更有意义。例如:$car_object = new carClass("$the_car"); 然后简单地执行 $car_object->drive(); - Taylor
我认为编写没有对象的函数更容易、更简短,你可以在函数名中放置类名,例如sec_do_check()、sec_redirect_home()等,比$ObjSecurity->redirect_home()要短得多。对于上面的例子,这是一个很好的例子,但是如果没有oop,直接包装function run($car_type) {...}就可以做得更短了。换句话说,你不需要为不同的汽车编写不同的函数,这完全是虚假的例子。除非你指定驱动程序正在做什么。即使你这样做,我也可以在没有oop的情况下写得更短。 - Petja Zaichikov

13

我会尝试将我的答案作为补充,因为Majd Taby和Coobird的回答非常好。

我多年来一直是一个过程式程序员,并没有反对面向对象编程,但从未真正看到它的重要性...直到我开始在团队中工作并构建更重要和复杂的项目。

在我看来,当您需要为更复杂的应用程序编写简洁、易于维护的代码时,面向对象编程真正发挥作用。请注意,并不是在每种情况下都适用,但有些情况下,过程式编程效果并不太好。

我大多数关于良好面向对象实现的例子都是针对那些有很多相关但又稍有不同的东西的项目。例如有很多表单、很多用户、很多产品的网站等等。

它们都有类似的行为名称,如print()、update()等等...但通过将它们封装为对象并在类中改变方法的实现,我可以使整个站点的运行时代码非常简单干净。此外,这里有一个关键点,尽管具有不同的行为,我仍然可以使用相同的方法调用处理不同的对象在整个应用程序中。这使得第二个开发人员可以处理实际的实现,而我则可以处理更深层次的代码。

我不知道这是否有所帮助,但作为不久前处于您目前状况的人来讲,我非常喜欢面向对象编程。


12

在编写程序时,使用面向对象编程方法而不是过程式编程方法,这并不完全取决于语言(无论是 PHP 还是其他语言),而是取决于您要解决的问题类型。

例如,如果您有一个程序,只需按顺序执行一堆函数,那么过程式编程就足够了。例如,如果它是一个简单的字符串操作程序,则过程式方法就足够了:

perform_truncation(my_string, 10)
to_upper(my_string)
perform_magic(my_string, hat, rabbit)

然而,如果你要处理许多不同的项(比如文件或其他对象的表示),那么面向对象的方法会更好。

例如,如果你有一堆汽车(Car),并希望它们能够行驶(drive),那么在过程式编程中,你可能会做类似以下的事情:

drive_car(first_car)
drive_car(second_car)

与此不同的是,在面向对象编程中,Car 可以自主驾驶:

RedCar myRedCar();
BlueCar myBlueCar();

myRedCar.drive();
myBlueCar.drive();

每辆汽车都属于不同的类别,因此它们的行为可以被定义得不同。此外,它们可能是相同的子类或,并且它们可能具有共同的功能。

实际上,采用哪种方法更好取决于问题的类型,有些问题用过程式编程方式解决更好,有些则需要采用面向对象编程方式。

除了过程式或面向对象的问题之外,一个拥有许多函数的源文件也可能成为“代码异味”。这同样适用于包含许多功能的类,这些功能最好在单独的类中作为单独的函数来执行。

这里的问题可能是代码组织,而不是决定选择过程式或面向对象编程。将函数组织成单独的源文件可能是所需的,而不是放弃使用过程式编写程序。

毕竟,有许多采用过程式编程方式编写的程序是编写良好且易于维护的。


6
假设我有一个包含50个函数的大文件,为什么我要在类中调用这些函数而不是直接使用function_name()呢?我应该切换并创建一个包含所有函数的对象吗?
转向面向对象编程(OOP)不应该被看作是你上述描述中简单的“切换”。
OOP需要完全不同的编程思维方式,需要重塑你的大脑。由于重塑大脑不是一夜之间就能完成的,许多人不愿意接受必要的重塑过程。不幸的是,这种重塑将需要投入时间和精力:研究、教程、试错。
这实际上涉及到退后一步,学习OOP背后的概念,但回报将是值得的,说话者是在互联网出现之前经历了这个过程的人。
一旦你真正理解了OOP,并且在日常生活中遵循了最佳实践,你会告诉别人你的编程生活已经变得更好了。
一旦你真正理解了OOP,你将自己回答了这个问题。

面向对象编程(OOP)只是编写MVC的一种方式,不使用OOP被认为是更好的选择。 - Petja Zaichikov

2

如果您将50个函数放入Utilities类中而不是50个静态方法,则会“污染”全局命名空间。

使用具有50个静态方法的类,方法名称仅在类内部有效。


同意!但是Codex没有提到他使用的是哪个版本。就我个人而言,我仍在使用5.2.6。 - Luc M
2
这并不是支持实际面向对象编程的论点,而本问题所讨论的恰恰是这个;相反,这与通常使用类将原本自由的方法命名空间化的模式有关。 - Rob
没有理由你不能在函数名称上小心一点。 - ceejayoz

2

我无法说哪个更好。但是根据我的经验,使用面向对象编程可以更好地管理代码。你知道哪个代码在哪里,哪个文件定义了哪些功能等等。

关于面向对象编程的运行时开销,我曾在某处读到(并且我认为这是正确的),如果你在常规函数中编写了糟糕的代码,并且在面向对象编程中编写了相同的糟糕代码,则函数版本的性能更好。因此,如果你的代码没有编写得很糟糕,那么就没有证据表明面向对象编程会使你的应用程序变慢。同时请记住,这些“慢”和“开销”都是以毫秒为单位衡量的。因此,如果你的应用程序没有为大量用户服务(例如每分钟超过100个用户),你可能感觉不到任何差异。


2
面向对象编程(OOP)允许您创建结构化的代码容器,称为类,它们可以彼此作为父/子类。这有助于构建应用程序,因为更易于维护,并且如果正确执行,可以减少代码冗余。OOP确实增加了一些开销,但并不明显,而且由于过程式代码的不可维护性而被弥补。如果您正在编写一个大型应用程序,尤其是如果将由多人共同开发,则一定要使用面向对象编程。
例如,假设您正在设计一个简单的网站。您可以创建一个页面对象。页面对象负责从数据库中获取页面的各种设置,例如元数据、标题标签甚至页面上某些“组件”的数量和类型(例如日历控件、小部件等)。
然后,您可以创建另一个类,比如Index,它扩展了Page。Index将是索引或主页。如果您有产品目录,您可以让Catalog类扩展Page。由于您的目录部分和主页都需要从数据库中获取页面元数据和基本构造,因此拥有一个已经为您处理的对象非常有帮助。在这两种情况下,页面执行所有工作并从数据库获取页面数据,将其加载到变量中,这些变量可以在您的索引类和目录类中访问。您不必在编写的每个页面中再次编写代码以进入数据库并获取它。
现在还有其他方法可以过程化地做到这一点,例如使用包含文件。但是,您会发现自己犯的错误和错误更少。例如,您可以在Page类中定义一个抽象方法。这意味着必须在扩展它的任何对象中定义此方法。因此,假设您在Page类中创建了一个setPageAttributes()函数作为抽象方法。当您这样做时,将创建一个空函数。当您创建索引类时,您必须创建setPageAttributes()函数(带有填充意图,例如访问Page类中定义的变量并将其用于设置实际元素在页面、模板或视图上)或者您将收到PHP错误。
如果您正在与其他人一起完成项目编写,则抽象方法将告诉对方“嘿,您需要在您编写的任何代码中定义这些函数”。这强制应用程序保持一致。
最后,如果不使用OOP,则无法使用MVC格式等框架。虽然不需要使用MVC,也存在一些争议,但它确实将应用程序的所有组件分开,并且在许多人(设计师、编码人员、营销员工)共同开发的环境中是必需的。

2
使用面向对象编程的好处如下:
  1. 结构化
  2. 可重用性
  3. 易于维护
  4. 数据封装
当需要创建一个包含50个函数的大文件时,你可以这样做,但是在函数流程和数据如何在每个函数之间绑定方面会遇到最大的问题。
此外,如果您希望将来替换流程的最大部分以进行维护,相信我,您必须进入每个函数并对其进行修改。而且,您永远不知道您的函数在代码的其他部分中如何使用。因此,始终建议使用面向对象编程。

1
接受的答案似乎忽略了一个事实,即可以根据变量名调用函数,例如在这个例子中:
function drive($the_car){
    $the_car();
}

诚然,在这种情况下,每辆汽车都需要一个功能,但这比建议的switch语句更有效率。

可以轻松地提供其他变量,如下所示:

function operate($the_car,$action){
    $the_car($action);
}

function ferrari($action){
    switch($action){
        case 'drive':
            echo 'Driving';
            break;

        case 'stop':
            echo 'Stopped';
            break;

        default: return;
    }
}


operate('ferrari','drive');

这里有一个switch语句,但它是为了提供原始示例中没有的其他功能,因此它绝不是矛盾的。

0

在PHP中使用面向对象编程(OOPs)的概念,以确保代码的安全性。所有的查询都是在函数文件中编写而不是代码文件中,因此没有人可以轻易地入侵我们的代码。因此,在PHP中最好使用类来代替直接编写查询。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接