phespro / phespro
一个具有意见、最小化和无缓存的开源PHP框架。
Requires
- php: ^8.2
- ext-pdo: *
- laminas/laminas-diactoros: ^3.1
- laminas/laminas-httphandlerrunner: ^2.7
- league/route: ^5.1
- mschop/notee: ^1.0.1
- phespro/container: ^1.0
- psr/log: ^3.0
- symfony/console: ^6.3
Requires (Dev)
- infection/infection: ^0.27
- phpunit/phpunit: ^10.3
README
另一个PHP框架?是的,这里有原因
- 缓存导致复杂性 -> 无内置缓存。
- 最小化 -> 大多数框架做得太多。您可以自由选择自己的工具。
- 稳定 -> 由于其最小化,更新到新版本应该很容易
- 简单 -> 设置简单,易于理解
- 现代 -> 使用现代PHP(>=8.2)构建
- 可扩展 -> 非常简单可扩展
设置
您需要composer来设置Phespro(Composer安装请参阅:https://getcomposer.org.cn)。如果您已安装composer,可以运行以下命令,这将使用我们的项目模板设置一个新项目:
composer create-project phespro/project your_project_name
或者,您可以将phespro添加到您的项目中并手动设置
composer require phespro/phespro
内核、容器和扩展
Phespro基于依赖注入容器构建。Phespro中发生的几乎所有事情都是通过容器完成的。因此,类 \Phespro\Phespro\Kernel
是 \Phespro\Container\Container
的子类。
Phespro基于扩展构建。在编写您的应用程序时,您至少需要构建一个扩展。
在创建内核时注册扩展。
$kernel = new Kernel([
MyExtension::class,
]);
请注意,您的扩展将按照它们在创建内核时传递的扩展数组中的顺序执行。
您的扩展类需要实现接口 Phespro\Phespro\Extensibility\ExtensionInterface
。
use Phespro\Phespro\Kernel;
use League\Route\Router;
class MyExtension implements Phespro\Phespro\Extensibility\ExtensionInterface
{
static function preBoot(Kernel $kernel): void
{
// primarily used for registering your extension service in the dependency injection container
$kernel->add(static::class, fn() => new static, ['extension']);
}
function boot(Kernel $kernel): void
{
// here you can register all your services. This includes actions (for web request handling).
$kernel->add(IndexGet::class, fn() => new IndexGet);
}
function bootHttp(Router $router): void
{
// register your routes and middlewares
$router->get('/', IndexGet::class));
}
}
出于简单起见,您可以使用特质 \Phespro\Phespro\NoTee\NoTeeTrait
。使用此特质,NoTee将自动注入到您的服务中。通过使用此特质,您可以在操作类中调用 $this->renderString()
和 $this->renderResponse()
。
当使用 项目模板 时,您已经注册了第一个扩展。当不包括项目模板时,您可以考虑查看 项目模板代码 以正确设置Phespro。
迁移
Phespro自带对迁移的支持。可以使用迁移迁移任何内容。由于Phespro不关心您使用哪种类型的数据库,您可以将迁移适配到任何数据库或存储。
在使用迁移系统之前,您需要为接口 Phespro\Phespro\Migration\MigrationStateStorageInterface
提供一个实现。
Phespro自带SQLite的实现。您可以通过注册所需的服务使用此实现。
// assumes, that the service 'db' is registered and provides a pdo connection to an sqlite db
$kernel->add(MigrationStateStorageInterface::class, fn(Container $c) => new SQLiteMigrationStateStorage(
$c->get('db'))
);
您可以通过执行以下命令简单地生成迁移:
bin/console migration:create --directory the/directory/path/of/your/migrations --namespace App
现在您可以通过将迁移添加到扩展的 boot
方法中注册迁移。
$kernel->add(Migration1000::class, fn() => new Migration1000, ['migration']);
现在您可以通过运行 bin/console migration:apply-all
来执行迁移。
路由/中间件
Phespro使用phpleague的路由实现。您可以在以下位置找到文档
https://route.thephpleague.com/
您可以在扩展的 bootHttp
方法中简单地添加路由和中间件。
ORM
我们认为,并不是每个应用程序都应该附带ORM。如果您想使用ORM,只需选择您想使用的ORM。
模板引擎
Phespro自带预安装的库NoTee,用于生成HTML。您可以选择使用这个库(推荐)或者安装您想要的任何模板引擎。
验证
Phespro不提供任何验证引擎。选择最适合您需求的验证引擎。
https://packagist.org.cn/?query=validation
日志记录
使用Phespro时,您需要明确激活日志记录功能。我们希望给您选择日志记录的自主权。默认情况下,使用NullLogger
,这相当于将日志发送到/dev/null
。这意味着,除非您明确激活日志记录,否则不会记录任何内容。
您可以通过用decorate
函数替换服务\Psr\LoggerInterface
来激活日志记录。您的日志记录器必须实现接口Psr\LoggerInterface
。
以下示例使用Monolog
$container->decorate(\Psr\LoggerInterface::class, function() { $logger = new Logger('MyLogger'); $logger->pushHandler(new StreamHandler('/path/to/your/logfile.log')); return $logger; });
配置
大多数框架的配置方式都非常复杂。大多数框架使用JSON、YAML或XML等格式,或者使用PHP数组。由于这两种方法在Phespro中都是可能的,因此Phespro中惯用的方法是使用配置类。配置类是普通的PHP类,代表配置数据结构。
以下示例提供MySQL数据库连接的配置。首先,让我们创建一个类
readonly class DatabaseConfiguration { public function __construct( public string $host, public string $username, public string $password, public string $databaseName, public int $port = 3306, ) { } }
在您的扩展中,现在可以注册一个新的数据库配置服务
class MyExtension implements Phespro\Phespro\Extensibility\ExtensionInterface { // ... function boot(Kernel $kernel): void { $kernel->add(DatabaseConfiguration::class, function() { $fail = fn(string $name) => throw new \Exception("Missing environment variable $name"); return new DatabaseConfiguration( host: getenv('DATABASE_HOST') ?: $fail('DATABASE_HOST'), username: getenv('DATABASE_USER') ?: $fail('DATABASE_USER'), password: getenv('DATABASE_PASS') ?: $fail('DATABASE_PASS'), databaseName: getenv('DATABASE_NAME') ?: $fail('DATABASE_NAME'), port: getenv('DATABASE_PORT') ?: 3306, ); }); } // ... }
太棒了。我们现在有一个配置类,它比其他框架中的配置提供了更多的类型安全性。现在我们可以在需要数据的任何服务中简单地使用该配置
readonly class DatabaseService { public function __construct( protected DatabaseConfiguration $databaseConfiguration ) { } } class MyOtherExtension implements Phespro\Phespro\Extensibility\ExtensionInterface { // ... function boot(Kernel $kernel): void { $kernel->add(DatabaseService::class, fn(ContainerInterface $c) => new DatabaseService( databaseConfiguration: $c->get(DatabaseConfiguration::class), )); } // ... }
框架配置
如果您想使用框架配置,请查看类\Phespro\Phespro\Configuration\FrameworkConfiguration
。
事件系统
在许多情况下,使用装饰器模式是完全可以的。在某些情况下,您可能希望使用事件系统。在这种情况下,您可以使用您喜欢的任何事件库。一个好的选择可能是Symfony事件调度器。
如何使用
添加第一个操作/路由
将新路由添加到您的应用程序包括以下步骤
- 创建一个操作类。此操作类必须实现接口
\Phespro\Phespro\Http\ActionInterface
。 - 在扩展的
boot
方法中,将操作类注册到依赖注入容器中。 - 使用第2步中注册的服务(通过服务名称)注册路由。例如,为“GET /products”注册操作将是:
$router->get('/products', 'myServiceName')
如果您使用NoTee,可以使用特质\Phespro\Phespro\NoTee\NoTeeTrait
自动将NoTee服务注入到您的操作类中。