可以选择自定义类,但可以选择统一的类名

Having the option of customized classes but a unified class name

提问人:Pekka 提问时间:3/11/2010 最后编辑:Pekka 更新时间:3/11/2010 访问量:292

问:

假设您正在构建一个 Web 应用程序,该应用程序有一天会成为一个打包的产品,用户希望能够扩展和自定义它。

它带有一个核心库,由包含类的 PHP 文件组成:

/library/
/library/frontend.class.php
/library/filesystem.class.php
/library/backend.class.php

现在,假设您希望保留用户无法修补的干净核心。不过,您希望用户能够根据需要自定义每个螺母和螺栓。

我目前的想法是创建一个自动加载机制,当一个类被实例化时,首先加载核心包括:

/library/frontend.class.php

然后,它切换到目录并查看是否存在同名的 include:user

 /user/library/frontend.class.php

如果存在,它也包括它。

显然,用户 include 必须包含一个类定义,该类定义扩展了核心包含中的定义。

现在我的问题是,我将如何实例化这样的类?毕竟,我始终可以确定有一个定义:

class frontend_core

但我不能确定有没有一个

class frontend_user extends frontend_core

但是,我希望能够依赖并实例化一个类名,而不管该类是否有自定义扩展。

有没有一种聪明的方法、想法或模式来实现这一目标?

当然,我可以编写一个简单的工厂帮助函数,首先查找类,然后查找类并返回一个初始化的对象,但我真的希望尽可能保持干净和简单,因为正如我所说,它将是一个打包的产品。usercore

我正在寻找一种聪明的技巧或模式,它使用尽可能少的代码,并引入尽可能少的新功能。

PHP 哎呀

评论


答:

0赞 streetparade 3/11/2010 #1

我会在核心中实现钩子,这样用户就不必破解核心,但仍然可以使用钩子扩展核心

评论

1赞 Pekka 3/11/2010
@streetparade我已经在应用程序的各个地方使用了钩子系统。对于更深入的自定义,仍然需要重写或扩展核心类。我想提供这两种可能性。
3赞 wimvds 3/11/2010 #2

你为什么不遵循 Propel 使用的方法呢?生成基类,并且已经提供了一个空的 User 类(扩展基类),用户可以在其中放置其重写/特定的实现详细信息,并且在代码中始终引用 User 类。所以基本上你只是使用你所描述的逻辑的反面。

如果上面的解释不清楚,请查看 http://propel.phpdb.org/trac/wiki/Users/Documentation/1.4/QuickStart#a6.UsingtheGeneratedSQLandOMFiles 并为小型数据库生成代码。基类位于 om 文件夹中,(默认为空)用户类位于根文件夹中。

评论

0赞 Pekka 3/11/2010
如果没有自定义,我想将用户目录留空,但另一方面,这是一个好主意。它为用户提供了简单的入门入口点,甚至可以在空类文件中提供代码示例和解释。我会考虑的。
0赞 Gordon 3/14/2010
但它也增加了多余的类,当用户不使用它时要加载它,例如User_Frontend加Core_Frontend,而不是在用户选择使用默认值时只加载Core_Frontend。
0赞 Gordon 3/11/2010 #3

我认为当您也想使用继承时,使用单个文件名会更复杂。基本上必须知道在哪里可以找到这两个类。两者都必须包括在内。class user_frontend extends core_frontend

如果你只是想这样做,你可以使用 PHP5.3 的 class_alias 将 Frontend 指向要使用的主类。低于 5.3。你可以使用ServiceFinder,它知道如何将服务名称映射到类,然后使用或使用依赖注入框架获取前端。new Frontend$service->get('frontend')

编辑 我删除了之前给出的 Loader 代码,因为它正遭受这个问题的困扰。

0赞 symcbean 3/11/2010 #4

我会使用核心类的构造函数来确定要加载的用户类,然后在核心类中实现工厂方法来生成用户类的实例。通过保护用户类的构造函数,并让用户类扩展核心类,可以确保其他位置的代码无法实例化用户类。

C.

0赞 Gabriel Solomon 3/11/2010 #5

你可以有一个加载器类来决定实例化哪个类:

Loader::instance()->load('Frontend')