Вариант 1 PHP: class CourseAction extends Base { public function __invoke(User $user) { $course = Course::findOne($user->course_id); $this->getView()->setTitle('Курс молодого бойца')->render("Course.$course->id", compact('user', 'course')); } } Вывод PHP: <?php use app\models\Course; /** * @var Course $course */ ?> <main class="container px-1"> <img src="/img/course/<?= $course->id ?>.jpg" class="w-100" alt="course-<?= $course->id ?>"> <?= $course->description ?> </main> Вариант 2 PHP: class CourseAction extends Base { public function __invoke(User $user) { $this->getView()->setTitle('Курс молодого бойца')->render("Course.$user->course_id", compact('user')); } } Вывод PHP: <?php use app\models\Course; use app\models\User; /** * @var User $user */ ?> <main class="container px-1"> <img src="/img/course/<?= $user->course_id ?>.jpg" class="w-100" alt="course-<?= $user->course_id ?>"> <?= Course::findOne($user->course_id)->description ?> </main> Какой вариант предпочтительнее?
в шаблонах не должен находится PHP index PHP: <h2>Index</h2> {<{@lastUsername}>} <p><a href="/registration">Регистрация</a></p> <p><a href="/login">Авторизация</a></p> <p><a href="/logout">Выход</a></p> <p><a href="/panel">Панель управления</a></p> Controller PHP: <?php declare ( strict_types = 1 ); namespace Nouvu\Resources\Controllers; use Nouvu\Framework\Http\Controllers\AbstractController; use Nouvu\Framework\View\Repository\CommitRepository; use Nouvu\Resources\System\RestApi; use function Nouvu\Resources\System\Helpers\{ isAjax, routerPathByName }; final class MainController extends AbstractController { public function index(): CommitRepository { $this -> setThreadTitles( 'Главная', 'Не главная' ); return $this -> render( 'index' ); } public function err404( string | int $_route ): CommitRepository { $this -> setThreadTitles( 'Страница не найдена' ); if ( isAjax() ) { return $this -> customJson( RestApi :: notFound() -> redirect( routerPathByName( $_route ) ) ); } return $this -> render( 'error.404', 'error-template' ); } public function err500( string | int $_route ): CommitRepository { $this -> setThreadTitles( 'Ошибка сервера' ); if ( isAjax() ) { return $this -> customJson( RestApi :: serverError() -> redirect( routerPathByName( $_route ) ) ); } return $this -> render( 'error.500', 'error-template' ); } } Helpers PHP: <?php declare ( strict_types = 1 ); namespace Nouvu\Resources\System\Helpers; use Nouvu\Framework\Foundation\Application; use Nouvu\Framework\Component\{ Config\Repository, Database\DatabaseManager, Validator\Exception\ViolationsException }; use Nouvu\Resources\Entity\Database\{ Permissions }; use Symfony\Component\HttpFoundation\{ Request, Response, Session\SessionInterface }; use Symfony\Component\Security\Core\{ Security, User\UserInterface, Exception\AuthenticationException }; function app( Application $data = null ): Application { static $app; return $app ??= $data; } function container( string $offset = null ): mixed { if ( is_null ( $offset ) ) { return app() -> container; } return app() -> container -> get( $offset ); } function lastUsername(): string { return app() -> session -> get( Security :: LAST_USERNAME, '' ); } .....
@MouseZver понял Вас: Вариант 1 функции твои понравились интересный подход, я ещё видел что-то вроде PHP: $app = new Application(); $_SERVER['app'] = &$app; if (!function_exists('app')) { function app() { return $_SERVER['app']; } } прокомментируешь может, если не лень
Полнейшая дичь. Сервер - это сервер, пихать туда свои данные не надо. Многие делают App паттерном синглтон и это один из редких случаев когда этот паттерн уместен.
ну тоже, как вариант, но проще в самом App сделать статичное свойство, например, public static $here, присвоить ему в конструкторе this и обращаться, где нужно App::$here
Мой класс App покрывает удобство использование DI-контейнера и не более, а хелпер делает его "глобальным" для использования PHP: <?php $app -> session -> get( 'KEY_NAME', 'DEFAULT_VALUE' ); Вместо: PHP: <?php $container -> get( 'session' ) -> get( 'KEY_NAME', 'DEFAULT_VALUE' ); $_SERVER $_FILES $_COOKIE $_POST $_GET - относится к Request данным, а не хранилище для впихивания чего-то из логики скрипта. --- Добавлено --- PHP: <?php declare ( strict_types = 1 ); namespace Nouvu\Framework\Foundation; use Psr\Container\ContainerInterface; class Application { //use ApplicationTrait; public function __construct ( private ContainerInterface $ContainerInterface, array $tools ) { foreach ( $tools + [ \App :: class => ( fn( ContainerInterface $ContainerInterface ): self => $this ) ] AS $name => $packaging ) { //$this -> setContainer( $name, $packaging ); $this -> ContainerInterface -> set( $name, $packaging ); } } /*protected function setContainer( string $name, callable $packaging ): void { $this -> ContainerInterface -> set( $name, $packaging ); }*/ /*protected function getContainer( string $name ): mixed { return $this -> ContainerInterface -> get( str_replace ( '.', '\\', $name ) ); }*/ public function __set( string $name, callable $value ): void { //$this -> setContainer( $name, $value ); $this -> ContainerInterface -> set( $name, $packaging ); } public function __get( string $name ): mixed { //return $this -> getContainer( $name ); return $this -> ContainerInterface -> get( str_replace ( '.', '\\', $name ) ); } public function init(): void { foreach ( $this -> repository ?-> get( 'app.ini_set' ) ?? [] AS $option => $value ) { ini_set ( $option, ( string ) $value( $this ) ); } } } --- Добавлено --- даже сейчас увидел недостаток в App
в каком-то месте неожиданно App::$here = 'Синглтон App накрылся тазиком'; App::$here->а_гдей-то_мой_метод
Что-то по-джуновски... Сделать приватным свойство, с доступом через статический метод. PHP: <?php class App { private static $instance; /** * Защищаем от прямого вызова */ protected function __construct() {} /** * Доступ к экземпляру */ public static function getInstance(): App { if(!self::$instance) { self::$instance = new App; } return self::$instance; } } // Используем: $app = new App; // ERROR $app = App::getInstance(); // App } Еще можно добавить защиту от сериализации, но мне лень...
Есть одно НО Сколько надо ума чтобы главный, стартовый класс инициализировать множество раз. Тот же composer, есть любители со времен Wordpress пихать инклуд по всему проекту. Окей, для таких существует *_once Поэтому за пределами "веб" шаринга, держим папку проекта и в ней существует один как bootstrap главный файл, откуда начинается подключение всего остального. /Хостинг/Приложение/service.php /Хостинг/www/index.php service.php PHP: <?php use Nouvu\Framework\Foundation\Application; $composer = require 'vendor/autoload.php'; return static function ( string $name ) use ( $composer ): Application { $composer -> addPsr4( \Nouvu\Resources :: class . '\\', __DIR__ . "/{$name}/Resources" ); return new Application( new \Nouvu\Container\Container, include __DIR__ . "/{$name}/tools.php" ); }; index.php PHP: <?php $service = require dirname ( __DIR__, 2 ) . '/Nouvu/service.php'; $app = $service( 'userdata' ); $app -> repository -> set( 'app.system.directory.site', __DIR__ ); $app -> kernel -> send(); Начиная с Kernel, включается возможность использовать helpers функции. Вся задумка полностью в Lazy работе. Т.е. подключается то, что требуется, не трогая остальное. в Конфиге так же есть возможность прописать "что нужно в первую очередь запустить" как "обязательное" --- Добавлено --- app.system.directory.site - если кто-то не допонял, это многомерный массив ['app']['system']['directory']['site'] Программисту удобнее в ООП, без вырви глаза.