This commit is contained in:
2025-12-01 06:39:04 +08:00
parent 79ce7142d9
commit 89ac36c227
10 changed files with 1093 additions and 14 deletions
+8
View File
@@ -0,0 +1,8 @@
<nav style="background: #f0f0f0; padding: 10px;">
<ul style="list-style: none; display: flex; gap: 20px; margin: 0; padding: 0;">
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
<li><a href="/contact">联系</a></li>
</ul>
</nav>
+42
View File
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Kiri Blade 示例')</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
background: #333;
color: white;
padding: 1rem;
margin-bottom: 2rem;
}
footer {
background: #f5f5f5;
padding: 1rem;
margin-top: 2rem;
text-align: center;
}
</style>
</head>
<body>
<header>
<h1>@yield('header', 'Kiri Blade 模板引擎')</h1>
</header>
<main>
@yield('content')
</main>
<footer>
<p>&copy; {{ date('Y') }} Kiri Framework. 使用 Blade 模板引擎构建。</p>
</footer>
</body>
</html>
+53
View File
@@ -0,0 +1,53 @@
<?php
/**
* Blade 模板引擎测试示例
*
* 使用方法:
* php examples/test-blade.php
*/
require_once __DIR__ . '/../vendor/autoload.php';
use Kiri\Router\Blade\BladeFactory;
use Kiri\Router\Blade\BladeHelper;
// 设置视图路径和缓存路径
$viewPath = __DIR__ . '/';
$cachePath = __DIR__ . '/cache';
// 创建 BladeFactory 实例
$factory = new BladeFactory($viewPath, $cachePath);
BladeHelper::setFactory($factory);
// 准备测试数据
$data = [
'name' => '张三',
'email' => 'zhangsan@example.com',
'age' => 28,
'skills' => ['PHP', 'JavaScript', 'MySQL', 'Redis'],
'posts' => [
[
'title' => 'Blade 模板引擎介绍',
'content' => '这是一个类似 Laravel Blade 的模板引擎实现。',
'date' => '2024-01-15'
],
[
'title' => '如何使用 Blade',
'content' => 'Blade 提供了简洁优雅的模板语法。',
'date' => '2024-01-20'
],
]
];
// 渲染视图
try {
echo "开始渲染视图...\n\n";
$html = $factory->render('user.profile', $data);
echo $html;
echo "\n\n渲染完成!\n";
} catch (\Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
echo "文件: " . $e->getFile() . "\n";
echo "行号: " . $e->getLine() . "\n";
}
+54
View File
@@ -0,0 +1,54 @@
@extends('layouts.app')
@section('title')
用户资料 - Kiri Blade
@endsection
@section('header')
用户资料页面
@endsection
@section('content')
<h2>用户信息</h2>
@if(isset($name))
<p><strong>姓名:</strong>{{ $name }}</p>
@else
<p>姓名未设置</p>
@endif
@if(isset($email))
<p><strong>邮箱:</strong>{{ $email }}</p>
@endif
@if(isset($age))
<p><strong>年龄:</strong>{{ $age }} </p>
@endif
<h3>技能列表</h3>
@if(isset($skills) && is_array($skills))
<ul>
@foreach($skills as $skill)
<li>{{ $skill }}</li>
@endforeach
</ul>
@else
<p>暂无技能</p>
@endif
<h3>文章列表</h3>
@if(isset($posts) && is_array($posts))
<div>
@foreach($posts as $post)
<div style="border: 1px solid #ddd; padding: 10px; margin: 10px 0;">
<h4>{{ $post['title'] ?? '无标题' }}</h4>
<p>{{ $post['content'] ?? '无内容' }}</p>
<small>发布时间:{{ $post['date'] ?? '未知' }}</small>
</div>
@endforeach
</div>
@else
<p>暂无文章</p>
@endif
@endsection
+408
View File
@@ -0,0 +1,408 @@
<?php
declare(strict_types=1);
namespace Kiri\Router\Blade;
/**
* Blade 模板编译器
* 将 Blade 语法编译为 PHP 代码
*/
class BladeCompiler
{
/**
* Blade 指令映射
* @var array<string, string>
*/
protected array $directives = [];
/**
* 自定义指令处理器
* @var array<string, callable>
*/
protected array $customDirectives = [];
/**
* 编译后的模板缓存目录
*/
protected string $cachePath;
/**
* 视图文件目录
*/
protected string $viewPath;
/**
* @param string $viewPath 视图文件路径
* @param string $cachePath 编译缓存路径
*/
public function __construct(string $viewPath, string $cachePath)
{
$this->viewPath = rtrim($viewPath, '/\\');
$this->cachePath = rtrim($cachePath, '/\\');
$this->registerDefaultDirectives();
}
/**
* 注册默认指令
*/
protected function registerDefaultDirectives(): void
{
$this->directives = [
'if' => 'if',
'elseif' => 'elseif',
'else' => 'else',
'endif' => 'endif',
'foreach' => 'foreach',
'endforeach' => 'endforeach',
'for' => 'for',
'endfor' => 'endfor',
'while' => 'while',
'endwhile' => 'endwhile',
'break' => 'break',
'continue' => 'continue',
'switch' => 'switch',
'case' => 'case',
'default' => 'default',
'endswitch' => 'endswitch',
];
}
/**
* 编译模板文件
*
* @param string $view 视图名称
* @return string 编译后的 PHP 文件路径
*/
public function compile(string $view): string
{
$viewFile = $this->viewPath . '/' . str_replace('.', '/', $view) . '.blade.php';
if (!file_exists($viewFile)) {
throw new \RuntimeException("视图文件不存在: {$viewFile}");
}
$compiledPath = $this->getCompiledPath($view);
$compiledDir = dirname($compiledPath);
if (!is_dir($compiledDir)) {
mkdir($compiledDir, 0755, true);
}
// 如果源文件未修改,直接返回缓存的编译文件
if (file_exists($compiledPath) && filemtime($viewFile) <= filemtime($compiledPath)) {
return $compiledPath;
}
$content = file_get_contents($viewFile);
$compiled = $this->compileString($content);
file_put_contents($compiledPath, $compiled);
return $compiledPath;
}
/**
* 编译模板字符串
*
* @param string $content Blade 模板内容
* @param bool $skipLayouts 是否跳过布局编译(避免递归)
* @return string 编译后的 PHP 代码
*/
public function compileString(string $content, bool $skipLayouts = false): string
{
// 移除注释
$content = $this->compileComments($content);
// 编译 Echo 语句
$content = $this->compileEchos($content);
// 编译指令
$content = $this->compileDirectives($content);
// 编译布局和继承(如果未跳过)
if (!$skipLayouts) {
$content = $this->compileLayouts($content);
}
// 编译包含
$content = $this->compileIncludes($content);
// 编译原始 PHP
$content = $this->compilePhp($content);
return $content;
}
/**
* 编译注释 {{-- ... --}}
*
* @param string $content
* @return string
*/
protected function compileComments(string $content): string
{
return preg_replace('/\{\{--\s*(.*?)\s*--\}\}/s', '', $content);
}
/**
* 编译 Echo 语句
* {{ $var }} => <?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8'); ?>
* {!! $var !!} => <?php echo $var; ?>
*
* @param string $content
* @return string
*/
protected function compileEchos(string $content): string
{
// 编译转义的 Echo {{ }}
$content = preg_replace_callback('/\{\{\s*(.+?)\s*\}\}/', function ($matches) {
$expression = trim($matches[1]);
return "<?php echo htmlspecialchars({$expression}, ENT_QUOTES, 'UTF-8'); ?>";
}, $content);
// 编译原始 Echo {!! !!}
$content = preg_replace_callback('/\{!!\s*(.+?)\s*!!\}/', function ($matches) {
$expression = trim($matches[1]);
return "<?php echo {$expression}; ?>";
}, $content);
return $content;
}
/**
* 编译指令 @if, @foreach 等
*
* @param string $content
* @return string
*/
protected function compileDirectives(string $content): string
{
foreach ($this->directives as $directive => $phpDirective) {
$pattern = '/@' . $directive . '\s*\((.+?)\)/';
$replacement = "<?php {$phpDirective} ($1): ?>";
$content = preg_replace($pattern, $replacement, $content);
// 处理结束指令
$endPattern = '/@end' . $directive . '/';
$endReplacement = "<?php end{$phpDirective}; ?>";
$content = preg_replace($endPattern, $endReplacement, $content);
}
// 处理自定义指令
foreach ($this->customDirectives as $directive => $handler) {
$pattern = '/@' . $directive . '\s*(?:\((.+?)\))?/';
$content = preg_replace_callback($pattern, function ($matches) use ($handler) {
$expression = $matches[1] ?? '';
return $handler($expression);
}, $content);
}
// 处理 @else
$content = preg_replace('/@else\b/', '<?php else: ?>', $content);
// 处理 @elseif
$content = preg_replace('/@elseif\s*\((.+?)\)/', '<?php elseif ($1): ?>', $content);
// 处理 @case
$content = preg_replace('/@case\s*\((.+?)\)/', '<?php case $1: ?>', $content);
// 处理 @default
$content = preg_replace('/@default\b/', '<?php default: ?>', $content);
// 处理 @break 和 @continue
$content = preg_replace('/@break\b/', '<?php break; ?>', $content);
$content = preg_replace('/@continue\b/', '<?php continue; ?>', $content);
return $content;
}
/**
* 编译布局和继承
* @extends('layout')
* @section('content') ... @endsection
* @yield('content')
* @parent
*
* @param string $content
* @return string
*/
protected function compileLayouts(string $content): string
{
// 处理 @extends
if (preg_match('/@extends\s*\([\'"](.+?)[\'"]\)/', $content, $matches)) {
$layout = $matches[1];
$content = preg_replace('/@extends\s*\([\'"](.+?)[\'"]\)/', '', $content);
// 提取所有 @section
$sections = [];
$content = preg_replace_callback('/@section\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@endsection/s', function ($matches) use (&$sections) {
$name = $matches[1];
$sectionContent = trim($matches[2]);
$sections[$name] = $sectionContent;
return '';
}, $content);
// 获取布局内容
$layoutContent = $this->getLayoutContent($layout);
// 先编译 section 内容
$compiledSections = [];
foreach ($sections as $name => $sectionContent) {
$compiledSections[$name] = $this->compileString($sectionContent, true);
}
// 编译布局内容(跳过布局处理以避免递归)
$layoutContent = $this->compileString($layoutContent, true);
// 替换 @yield 为对应的 section 内容
foreach ($compiledSections as $name => $sectionContent) {
$layoutContent = preg_replace('/@yield\s*\([\'"](?:' . preg_quote($name, '/') . ')[\'"]\)/', $sectionContent, $layoutContent);
}
// 替换剩余的 @yield 为空
$layoutContent = preg_replace('/@yield\s*\([\'"](.+?)[\'"]\)/', '', $layoutContent);
return $layoutContent;
}
// 处理 @section ... @endsection (非继承模式,用于组件等)
$content = preg_replace_callback('/@section\s*\([\'"](.+?)[\'"]\)\s*(.*?)\s*@endsection/s', function ($matches) {
$name = $matches[1];
$sectionContent = trim($matches[2]);
// 处理 @parent
$sectionContent = preg_replace('/@parent/', '', $sectionContent);
return "<?php \$__sections['{$name}'] = function() { ?>{$sectionContent}<?php }; ?>";
}, $content);
// 处理 @yield(非继承模式)
$content = preg_replace_callback('/@yield\s*\([\'"](.+?)[\'"]\s*(?:,\s*[\'"](.+?)[\'"]\s*)?\)/', function ($matches) {
$name = $matches[1];
$default = $matches[2] ?? '';
if ($default) {
return "<?php echo isset(\$__sections['{$name}']) ? call_user_func(\$__sections['{$name}']) : '{$default}'; ?>";
}
return "<?php echo isset(\$__sections['{$name}']) ? call_user_func(\$__sections['{$name}']) : ''; ?>";
}, $content);
// 处理 @parent(在 section 中使用)
$content = preg_replace('/@parent/', '', $content);
return $content;
}
/**
* 编译包含 @include('view')
*
* @param string $content
* @return string
*/
protected function compileIncludes(string $content): string
{
return preg_replace_callback('/@include\s*\([\'"](.+?)[\'"]\s*(?:,\s*\[(.+?)\])?\)/', function ($matches) {
$view = $matches[1];
$dataStr = $matches[2] ?? '';
// 解析数据数组
if ($dataStr) {
// 尝试解析数组字符串,如果失败则使用空数组
try {
$data = eval("return [{$dataStr}];");
$dataCode = var_export($data, true);
} catch (\Throwable $e) {
$dataCode = '[]';
}
} else {
$dataCode = '[]';
}
// 使用静态方法调用,因为我们需要在运行时获取 BladeFactory 实例
return "<?php echo \Kiri\Router\Blade\BladeHelper::include('{$view}', {$dataCode}); ?>";
}, $content);
}
/**
* 编译原始 PHP @php ... @endphp
*
* @param string $content
* @return string
*/
protected function compilePhp(string $content): string
{
return preg_replace('/@php\s*(.*?)\s*@endphp/s', '<?php $1 ?>', $content);
}
/**
* 获取布局文件内容
*
* @param string $layout
* @return string
*/
protected function getLayoutContent(string $layout): string
{
$layoutFile = $this->viewPath . '/' . str_replace('.', '/', $layout) . '.blade.php';
if (!file_exists($layoutFile)) {
throw new \RuntimeException("布局文件不存在: {$layoutFile}");
}
return file_get_contents($layoutFile);
}
/**
* 获取编译后的文件路径
*
* @param string $view
* @return string
*/
protected function getCompiledPath(string $view): string
{
$hash = md5($view);
return $this->cachePath . '/' . substr($hash, 0, 2) . '/' . substr($hash, 2, 2) . '/' . $hash . '.php';
}
/**
* 注册自定义指令
*
* @param string $name 指令名称
* @param callable $handler 处理函数
*/
public function directive(string $name, callable $handler): void
{
$this->customDirectives[$name] = $handler;
}
/**
* 清除编译缓存
*
* @return void
*/
public function clearCache(): void
{
if (is_dir($this->cachePath)) {
$this->deleteDirectory($this->cachePath);
}
}
/**
* 递归删除目录
*
* @param string $dir
* @return void
*/
protected function deleteDirectory(string $dir): void
{
if (!is_dir($dir)) {
return;
}
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
}
rmdir($dir);
}
}
+144
View File
@@ -0,0 +1,144 @@
<?php
declare(strict_types=1);
namespace Kiri\Router\Blade;
/**
* Blade 视图工厂
* 管理视图路径、缓存和编译器
*/
class BladeFactory
{
/**
* 视图文件路径
*/
protected string $viewPath;
/**
* 编译缓存路径
*/
protected string $cachePath;
/**
* Blade 编译器实例
*/
protected ?BladeCompiler $compiler = null;
/**
* 共享数据(所有视图可用)
*/
protected array $shared = [];
/**
* @param string $viewPath 视图文件路径
* @param string $cachePath 编译缓存路径
*/
public function __construct(string $viewPath, string $cachePath)
{
$this->viewPath = rtrim($viewPath, '/\\');
$this->cachePath = rtrim($cachePath, '/\\');
}
/**
* 获取编译器实例
*
* @return BladeCompiler
*/
public function getCompiler(): BladeCompiler
{
if ($this->compiler === null) {
$this->compiler = new BladeCompiler($this->viewPath, $this->cachePath);
}
return $this->compiler;
}
/**
* 创建视图实例
*
* @param string $view 视图名称
* @param array $data 视图数据
* @return BladeView
*/
public function make(string $view, array $data = []): BladeView
{
// 合并共享数据
$data = array_merge($this->shared, $data);
return new BladeView($view, $data, $this->getCompiler());
}
/**
* 渲染视图
*
* @param string $view 视图名称
* @param array $data 视图数据
* @return string
*/
public function render(string $view, array $data = []): string
{
return $this->make($view, $data)->render();
}
/**
* 共享数据到所有视图
*
* @param string|array $key 键名或数据数组
* @param mixed $value 值(当 $key 为数组时忽略)
* @return $this
*/
public function share(string|array $key, mixed $value = null): self
{
if (is_array($key)) {
$this->shared = array_merge($this->shared, $key);
} else {
$this->shared[$key] = $value;
}
return $this;
}
/**
* 注册自定义指令
*
* @param string $name 指令名称
* @param callable $handler 处理函数
* @return $this
*/
public function directive(string $name, callable $handler): self
{
$this->getCompiler()->directive($name, $handler);
return $this;
}
/**
* 清除编译缓存
*
* @return void
*/
public function clearCache(): void
{
$this->getCompiler()->clearCache();
}
/**
* 获取视图路径
*
* @return string
*/
public function getViewPath(): string
{
return $this->viewPath;
}
/**
* 获取缓存路径
*
* @return string
*/
public function getCachePath(): string
{
return $this->cachePath;
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace Kiri\Router\Blade;
/**
* Blade 辅助函数
*/
class BladeHelper
{
/**
* 全局 BladeFactory 实例
*/
protected static ?BladeFactory $factory = null;
/**
* 设置全局 BladeFactory 实例
*
* @param BladeFactory $factory
*
* @return void
*/
public static function setFactory(BladeFactory $factory): void
{
self::$factory = $factory;
}
/**
* 获取全局 BladeFactory 实例
*
* @return BladeFactory
*/
public static function getFactory(): BladeFactory
{
if (self::$factory === null) {
$viewPath = APP_PATH . 'resources/view';
$cachePath = storage(null, 'view/cache');
self::$factory = new BladeFactory($viewPath, $cachePath);
}
return self::$factory;
}
/**
* 包含视图
*
* @param string $view
* @param array $data
*
* @return string
*/
public static function include(string $view, array $data = []): string
{
return self::getFactory()
->render($view, $data);
}
}
+86
View File
@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Kiri\Router\Blade;
/**
* Blade 视图类
* 管理视图的渲染和数据传递
*/
class BladeView
{
/**
* 视图名称
*/
protected string $view;
/**
* 视图数据
*/
protected array $data;
/**
* Blade 编译器实例
*/
protected BladeCompiler $compiler;
/**
* @param string $view 视图名称
* @param array $data 视图数据
* @param BladeCompiler $compiler 编译器实例
*/
public function __construct(string $view, array $data, BladeCompiler $compiler)
{
$this->view = $view;
$this->data = $data;
$this->compiler = $compiler;
}
/**
* 渲染视图
*
* @return string
*/
public function render(): string
{
// 编译视图
$compiledPath = $this->compiler->compile($this->view);
// 提取数据
extract($this->data, EXTR_SKIP);
// 开始输出缓冲
ob_start();
try {
// 包含编译后的 PHP 文件
require $compiledPath;
} catch (\Throwable $e) {
ob_end_clean();
throw new \RuntimeException("视图渲染失败: {$this->view}", 0, $e);
}
return ob_get_clean();
}
/**
* 获取视图名称
*
* @return string
*/
public function getView(): string
{
return $this->view;
}
/**
* 获取视图数据
*
* @return array
*/
public function getData(): array
{
return $this->data;
}
}
+217
View File
@@ -0,0 +1,217 @@
# Kiri Blade 模板引擎
这是一个类似 Laravel Blade 的模板引擎实现,用于 kiri-router 项目。
## 功能特性
- ✅ 变量输出:`{{ $variable }}``{!! $variable !!}`
- ✅ 控制结构:`@if`, `@elseif`, `@else`, `@endif`
- ✅ 循环:`@foreach`, `@endforeach`, `@for`, `@endfor`, `@while`, `@endwhile`
- ✅ 布局继承:`@extends`, `@section`, `@yield`, `@endsection`
- ✅ 包含视图:`@include`
- ✅ 注释:`{{-- comment --}}`
- ✅ 原始 PHP`@php ... @endphp`
- ✅ 编译缓存:自动缓存编译后的模板以提高性能
## 使用方法
### 基本用法
```php
use function Kiri\Router\View;
// 在控制器中渲染视图
return View('user.profile', [
'name' => 'John Doe',
'email' => 'john@example.com'
]);
```
### 视图文件结构
视图文件应放在 `resources/view` 目录下,使用 `.blade.php` 扩展名:
```
resources/
view/
layouts/
app.blade.php
user/
profile.blade.php
components/
header.blade.php
```
### 模板语法示例
#### 1. 变量输出
```blade
<!-- 转义输出 -->
<h1>{{ $title }}</h1>
<p>{{ $description }}</p>
<!-- 原始输出(不转义) -->
<div>{!! $htmlContent !!}</div>
```
#### 2. 条件语句
```blade
@if($user->isAdmin())
<p>管理员</p>
@elseif($user->isModerator())
<p>版主</p>
@else
<p>普通用户</p>
@endif
```
#### 3. 循环
```blade
@foreach($users as $user)
<div>
<h3>{{ $user->name }}</h3>
<p>{{ $user->email }}</p>
</div>
@endforeach
@for($i = 0; $i < 10; $i++)
<p>Item {{ $i }}</p>
@endfor
```
#### 4. 布局继承
**layouts/app.blade.php:**
```blade
<!DOCTYPE html>
<html>
<head>
<title>@yield('title', '默认标题')</title>
</head>
<body>
<header>
@include('components.header')
</header>
<main>
@yield('content')
</main>
<footer>
<p>&copy; 2024</p>
</footer>
</body>
</html>
```
**user/profile.blade.php:**
```blade
@extends('layouts.app')
@section('title')
用户资料
@endsection
@section('content')
<h1>用户资料</h1>
<p>姓名:{{ $name }}</p>
<p>邮箱:{{ $email }}</p>
@endsection
```
#### 5. 包含视图
```blade
@include('components.header')
@include('components.footer', ['year' => 2024])
```
#### 6. 注释
```blade
{{-- 这是注释,不会输出到 HTML --}}
```
#### 7. 原始 PHP
```blade
@php
$count = count($items);
$total = array_sum($prices);
@endphp
<p>总数:{{ $count }}</p>
```
## 高级用法
### 自定义指令
```php
use Kiri\Router\Blade\BladeHelper;
$factory = BladeHelper::getFactory();
// 注册自定义指令
$factory->directive('datetime', function ($expression) {
return "<?php echo date('Y-m-d H:i:s', {$expression}); ?>";
});
```
使用自定义指令:
```blade
@datetime(time())
```
### 共享数据
```php
use Kiri\Router\Blade\BladeHelper;
$factory = BladeHelper::getFactory();
// 共享数据到所有视图
$factory->share('siteName', 'My Website');
$factory->share([
'version' => '1.0.0',
'author' => 'Kiri Team'
]);
```
### 清除缓存
```php
use Kiri\Router\Blade\BladeHelper;
$factory = BladeHelper::getFactory();
$factory->clearCache();
```
## 配置
视图路径和缓存路径可以通过常量配置:
```php
// 视图路径
define('APP_PATH', __DIR__ . '/');
// 缓存路径(可选)
define('RUNTIME_PATH', __DIR__ . '/runtime');
```
默认情况下:
- 视图路径:`APP_PATH . 'resources/view'`
- 缓存路径:`RUNTIME_PATH . '/blade'` 或系统临时目录
## 注意事项
1. 模板文件必须使用 `.blade.php` 扩展名
2. 视图路径使用点号分隔,如 `user.profile` 对应 `user/profile.blade.php`
3. 编译后的模板会自动缓存,修改源文件后会自动重新编译
4. 建议在生产环境中定期清理缓存目录
+23 -14
View File
@@ -4,13 +4,17 @@ declare(strict_types=1);
namespace Kiri\Router;
use Kiri\Di\Interface\ResponseEmitterInterface;
use Kiri\Router\Blade\BladeFactory;
use Kiri\Router\Blade\BladeHelper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* @param string $path
* @param array $data
* 渲染 Blade 视图
*
* @param string $path 视图路径(支持 . 分隔,如 'user.profile'
* @param array $data 视图数据
*
* @return ResponseInterface
*/
@@ -18,21 +22,26 @@ function View(string $path, array $data = []): ResponseInterface
{
$response = \response();
$response->withAddedHeader('Content-Type', 'text/html; charset=utf-8');
try {
ob_start();
$__path = $path;
$__data = $data;
// 获取视图路径和缓存路径
$viewPath = APP_PATH . 'resources/view';
$cachePath = storage(null, 'view/cache');
extract($__data, EXTR_SKIP);
require APP_PATH . 'resources/view/' . $path . '.php';
$content = ltrim(ob_get_clean());
} catch (\Exception $e) {
$content = throwable($e);
} finally {
return $response->html($content);
// 创建或获取 BladeFactory 实例
$factory = BladeHelper::getFactory();
if ($factory->getViewPath() !== $viewPath) {
$factory = new BladeFactory($viewPath, $cachePath);
BladeHelper::setFactory($factory);
}
// 渲染视图
$content = $factory->render($path, $data);
} catch (\Exception $e) {
$content = function_exists('throwable') ? throwable($e) : $e->getMessage();
}
return $response->html($content);
}
/**