phespro/phespro

一个具有意见、最小化和无缓存的开源PHP框架。

1.6.2 2023-12-10 20:15 UTC

README

logo

另一个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。您可以选择使用这个库(推荐)或者安装您想要的任何模板引擎。

链接到NoTee文档

验证

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事件调度器

如何使用

添加第一个操作/路由

将新路由添加到您的应用程序包括以下步骤

  1. 创建一个操作类。此操作类必须实现接口\Phespro\Phespro\Http\ActionInterface
  2. 在扩展的boot方法中,将操作类注册到依赖注入容器中。
  3. 使用第2步中注册的服务(通过服务名称)注册路由。例如,为“GET /products”注册操作将是:$router->get('/products', 'myServiceName')

如果您使用NoTee,可以使用特质\Phespro\Phespro\NoTee\NoTeeTrait自动将NoTee服务注入到您的操作类中。