schmittjoh /cg-library似乎是我需要的,但根本没有文档。
这个库提供了一些生成 PHP 代码通常需要的工具。它的优势之一在于通过行为增强现有类。
给定A
类:
class A {}
当然,我想在运行时使用一些缓存机制 class 进行修改,A
使其实现给定的接口:
interface I
{
public function mustImplement();
}
mustImplement()
...具有类中方法的“默认”实现A
。
schmittjoh /cg-library似乎是我需要的,但根本没有文档。
这个库提供了一些生成 PHP 代码通常需要的工具。它的优势之一在于通过行为增强现有类。
给定A
类:
class A {}
当然,我想在运行时使用一些缓存机制 class 进行修改,A
使其实现给定的接口:
interface I
{
public function mustImplement();
}
mustImplement()
...具有类中方法的“默认”实现A
。
注意: OP 需要 PHP 5.3(以前没有这样标记),这个问题是 PHP 5.4 的概述。
您可以通过定义接口并添加包含这些接口的默认实现的特征来做到这一点。
然后你创建一个新的类定义
例如,请参阅PHP 中的特征 - 任何现实世界的示例/最佳实践?
您可以轻松地生成该类定义代码并将其存储include
或eval
直接存储。
如果您使新的类名包含它所包含的所有信息(在您的情况下是基类名和接口),您可以轻松地防止创建重复的类定义。
这无需任何 PHP 扩展(如 runkit)即可工作。如果您serialize
参与其中,您甚至可以在运行时使用新接口重载现有对象,以防它们可以序列化/反序列化。
您可以在以下位置找到已实现此功能的代码示例:
您还可以使用角色对象模式和良好的旧聚合。
与其拥有包含所有业务逻辑的智能实体,不如让它们变得愚蠢,然后将所有业务逻辑移动到聚合这些愚蠢实体的角色中。然后,您的行为是生活在角色中的一等公民。
例子:
interface BannableUser
{
public function ban();
}
具有一种特定行为的接口遵循接口隔离原则。它还极大地增加了重用的可能性,因为与具有特定应用程序行为集合的实体相比,您更有可能重用单个行为。
现在要实现它,您需要创建一个适当的角色类:
class BannableUserRole implements BannableUser
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function ban()
{
$this->user->isBanned = true;
}
}
您仍然有一个 User 实体,但它完全没有所有行为。它本质上只是一袋 Getter 和 Setter 或公共属性。它代表您的系统是什么。这是数据部分,而不是交互部分。交互现在在角色内部。
class User
{
public $isBanned;
// … more properties
}
现在假设您有某种 Web UI,您可以在控制器中执行以下操作:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$userId = $request->getVar('user_id');
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
您可以通过将 User 的实际查找和 Role 的分配移动到 UseCase 类中来进一步解耦。我们称之为上下文:
class BanUserContext implements Context
{
public function run($userId)
{
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
现在,您在模型层中拥有了所有业务逻辑,并且与您的用户界面完全隔离。上下文是您的系统所做的。您的控制器只会委托给适当的上下文:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$this->banUserContext->run($request->getVar('user_id'));
}
}
就是这样。不需要 Runkit 或类似的黑客。以上是数据上下文交互架构模式的简化版本,以防您想进一步研究。
我需要一个工具来编辑 PHP 类(特别是 Doctrine Entities),我找不到它,所以我创建了一个可以帮助你的工具,我大量记录了它。因此,如果您想尝试一下,我很乐意提供帮助。
在这里,SourceEditor
它为您提供了这样的 API:
/* @var $classEditor DocDigital\Lib\SourceEditor\PhpClassEditor */
$classEditor->parseFile($classPath);
$classEditor->getClass('a')->getMethod('b')->addAnnotation('@auth Juan Manuel Fernandez <juanmf@gmail.com>');
$classEditor->getClass('a')->getAttribute('attr')->addAnnotation('@Assert\Choice(...)');
$classEditor->getClass('a')->addAttribute($attr2);
$classEditor->getClass('a')->addUse('use DocDigital\Bundle\DocumentBundle\DocumentGenerator\Annotation as DdMapping;');
$classEditor->getClass('a')->addConst(' const CONSTANT = 1;');
file_put_contents($classPath, $classEditor->getClass('a')->render(false));
Runkit扩展可以帮助你
Runkit_Sandbox — Runkit Sandbox Class -- PHP Virtual Machine
Runkit_Sandbox_Parent — Runkit Anti-Sandbox Class
runkit_class_adopt — Convert a base class to an inherited class, add ancestral methods when appropriate
runkit_class_emancipate — Convert an inherited class to a base class, removes any method whose scope is ancestral
runkit_constant_add — Similar to define(), but allows defining in class definitions as well
runkit_constant_redefine — Redefine an already defined constant
runkit_constant_remove — Remove/Delete an already defined constant
runkit_function_add — Add a new function, similar to create_function
runkit_function_copy — Copy a function to a new function name
runkit_function_redefine — Replace a function definition with a new implementation
runkit_function_remove — Remove a function definition
runkit_function_rename — Change the name of a function
runkit_import — Process a PHP file importing function and class definitions, overwriting where appropriate
runkit_lint_file — Check the PHP syntax of the specified file
runkit_lint — Check the PHP syntax of the specified php code
runkit_method_add — Dynamically adds a new method to a given class
runkit_method_copy — Copies a method from class to another
runkit_method_redefine — Dynamically changes the code of the given method
runkit_method_remove — Dynamically removes the given method
runkit_method_rename — Dynamically changes the name of the given method
runkit_return_value_used — Determines if the current functions return value will be used
runkit_sandbox_output_handler — Specify a function to capture and/or process output from a runkit sandbox
runkit_superglobals — Return numerically indexed array of registered superglobals