无框架PHP项目组件组织及依赖控制器存储位置咨询
Hey there! Since you’re coming from a framework background, building a framework-less PHP project can feel a little unstructured at first—totally get that confusion. Let’s break down how to organize your components properly, especially where to put those dependent controllers/reusable logic.
1. Where to Store Dependent Controllers & Reusable Components
First, let’s clarify terms to avoid mixing responsibilities:
- Base Controllers: If you have a controller that other route-specific controllers inherit from (e.g., it handles view rendering, request validation, or shared auth checks), stick it in a subdirectory like
controllers/Base/(e.g.,BaseController.php). This keeps your route controllers clean and focused. - Reusable Business Logic: If you’re talking about components that aren’t directly tied to a route (like user authentication logic, order processing, or data fetching), these don’t belong in the
controllers/folder at all. Instead, use aservices/directory—this is where your core business logic lives, and route controllers will call these services to get work done. - Middleware: For code that runs before/after your controllers (like logging, auth checks, or request sanitization), create a
middleware/directory. This keeps cross-cutting concerns separate from your core app logic. - Core Infrastructure: If you have foundational components (like a router, database connection wrapper, or request/response handlers), put them in a
core/directory. These are the "framework-like" bits you’re building yourself.
2. A Scalable, Clean Directory Structure
Here’s a standard, maintainable structure that aligns with separation of concerns:
your-project/ ├── public/ # Web root (only this folder is accessible to the web) │ └── index.php # Single entry point for all requests ├── app/ # Your application's core code │ ├── controllers/ # Route-specific controllers (only handle request/response) │ │ ├── Base/ │ │ │ └── BaseController.php │ │ ├── HomeController.php │ │ └── UserController.php │ ├── services/ # Business logic layer (called by controllers) │ │ ├── UserService.php │ │ └── OrderService.php │ ├── models/ # Data models (map to database tables, handle ORM/CRUD) │ │ ├── User.php │ │ └── Order.php │ ├── middleware/ # Pre/post request handlers │ │ ├── AuthMiddleware.php │ │ └── LoggingMiddleware.php │ ├── views/ # Template files (HTML/PHP for rendering) │ │ ├── layouts/ # Reusable page layouts (header, footer) │ │ │ ├── header.php │ │ │ └── footer.php │ │ ├── home/ │ │ │ └── index.php │ │ └── user/ │ │ └── profile.php │ └── core/ # Custom framework-like tools │ ├── Router.php │ ├── Database.php │ ├── Request.php │ └── Response.php ├── config/ # Configuration files (DB settings, routes, env vars) │ ├── database.php │ ├── routes.php │ └── env.php ├── vendor/ # Composer dependencies (if you use Composer) └── logs/ # Application logs
3. Key Practices to Keep Things Maintainable
- Separation of Concerns: Never let controllers handle business logic. Controllers should only accept requests, call the right service, and send back responses. All "heavy lifting" goes to services.
- Use Autoloading: Ditch manual
require_oncecalls by using Composer’s PSR-4 autoloading. Add this to yourcomposer.json:
Run"autoload": { "psr-4": { "App\\": "app/" } }composer dump-autoloadto set it up, and you’ll be able to reference classes likeApp\Services\UserServicewithout manual includes. - Dependency Injection: Instead of instantiating services directly in controllers, inject them via the constructor. This makes your code easier to test and modify:
class UserController extends BaseController { private $userService; public function __construct(\App\Services\UserService $userService) { $this->userService = $userService; } public function profile($userId) { $user = $this->userService->getUserById($userId); return $this->render('user/profile', ['user' => $user]); } } - Centralize Routing: Keep all route definitions in
config/routes.phpinstead of scattering them in controllers. Example:
Then build areturn [ 'GET /' => 'App\Controllers\HomeController@index', 'GET /user/{id}' => 'App\Controllers\UserController@profile', 'POST /user/login' => 'App\Controllers\UserController@login', ];core/Router.phpto parse these routes and dispatch requests to the right controller methods.
By following this structure, you’ll keep your project organized, scalable, and easy to maintain—even without a full framework.
内容的提问来源于stack exchange,提问作者bulicud
相关产品推荐
相关产品推荐

