컨트롤러

새로운 컨트롤러 파일 app/controller/FooController.php를 만듭니다.

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function index(Request $request)
    {
        return response('hello index');
    }

    public function hello(Request $request)
    {
        return response('hello webman');
    }
}

http://127.0.0.1:8787/foo에 접근하면 페이지가 hello index를 반환합니다.

http://127.0.0.1:8787/foo/hello에 접근하면 페이지가 hello webman을 반환합니다.

물론 라우트 설정을 통해 라우트 규칙을 변경할 수 있으며, 자세한 내용은 라우트를 참조하세요.


404 오류가 발생하여 접근할 수 없는 경우 config/app.php을 열고 controller_suffixController로 설정한 다음 재시작하세요.

컨트롤러 접미사

webman은 1.3 버전부터 config/app.php에서 컨트롤러 접미사를 설정하는 것을 지원합니다. 만약 config/app.php에서 controller_suffix가 빈 문자열 ''로 설정된 경우, 컨트롤러는 다음과 같이 보일 것입니다.

app\controller\Foo.php입니다.

<?php
namespace app\controller;

use support\Request;

class Foo
{
    public function index(Request $request)
    {
        return response('hello index');
    }

    public function hello(Request $request)
    {
        return response('hello webman');
    }
}

강력하게 컨트롤러 접미사를 Controller로 설정하는 것을 추천합니다. 이렇게 하면 컨트롤러와 모델 클래스 이름의 충돌을 피할 수 있으며, 보안성을 높일 수 있습니다.

설명

  • 프레임워크는 support\Request 객체를 자동으로 컨트롤러에 전달합니다. 이를 통해 사용자 입력 데이터(get, post, header, cookie 등)를 가져올 수 있습니다. 자세한 내용은 요청을 참조하세요.
  • 컨트롤러는 숫자, 문자열 또는 support\Response 객체를 반환할 수 있지만, 다른 유형의 데이터는 반환할 수 없습니다.
  • support\Response 객체는 response(), json(), xml(), jsonp(), redirect() 등의 헬퍼 함수를 통해 생성할 수 있습니다.

컨트롤러 매개변수 바인딩

예제

webman은 컨트롤러 메서드 매개변수를 통해 요청 매개변수를 자동으로 바인딩하는 것을 지원합니다. 예를 들어,

<?php
namespace app\controller;
use support\Response;

class UserController
{
    public function create(string $name, int $age): Response
    {
        return json(['name' => $name, 'age' => $age]);
    }
}

GET 또는 POST 방식으로 nameage의 값을 전달할 수 있으며, 라우트 매개변수를 통해 nameage 매개변수를 전달할 수도 있습니다. 예를 들어,

Route::any('/user/{name}/{age}', [app\controller\UserController::class, 'create']);

우선 순위는 라우트 매개변수 > GET > POST 매개변수입니다.

기본값

/user/create?name=tom에 접근한다고 가정하면, 다음과 같은 오류가 발생합니다.

Missing input parameter age

이유는 age 매개변수를 전달하지 않았기 때문이며, 기본값을 설정하여 이 문제를 해결할 수 있습니다. 예를 들어,

<?php
namespace app\controller;
use support\Response;

class UserController
{
    public function create(string $name, int $age = 18): Response
    {
        return json(['name' => $name, 'age' => $age]);
    }
}

매개변수 유형

/user/create?name=tom&age=not_int에 접근하면 다음과 같은 오류가 발생합니다.


테스트를 용이하게 하기 위해 브라우저 주소창에 직접 매개변수를 입력합니다. 실제 개발에서는 POST 방식을 통해 매개변수를 전달해야 합니다.

Input age must be of type int, string given

이는 수신된 데이터가 유형에 따라 변환되며, 변환할 수 없는 경우 support\exception\InputTypeException 예외가 발생하기 때문입니다. 전달된 age 매개변수가 int 유형으로 변환할 수 없으므로 위와 같은 오류가 발생했습니다.

사용자 정의 오류

다음 명령으로 다음과 같은 오류 메시지 Missing input parameter ageInput age must be of type int, string given을 다국어로 사용자 정의할 수 있습니다.

composer require symfony/translation
mkdir resource/translations/zh_CN/ -p
echo "<?php
return [
    'Input :parameter must be of type :exceptType, :actualType given' => '입력 매개변수 :parameter는 :exceptType 유형이어야 하며, 전달된 유형은 :actualType입니다.',
    'Missing input parameter :parameter' => '입력 매개변수 :parameter가 누락되었습니다.',
];" > resource/translations/zh_CN/messages.php
php start.php restart

기타 유형

webman이 지원하는 매개변수 유형은 int, float, string, bool, array, object, 클래스 인스턴스 등입니다. 예를 들어,

<?php
namespace app\controller;
use support\Response;

class UserController
{
    public function create(string $name, int $age, float $balance, bool $vip, array $extension): Response
    {
        return json([
            'name' => $name,
            'age' => $age,
            'balance' => $balance,
            'vip' => $vip,
            'extension' => $extension,
        ]);
    }
}

/user/create?name=tom&age=18&balance=100.5&vip=true&extension[foo]=bar에 접근하면 다음과 같은 결과를 얻습니다.

{
  "name": "tom",
  "age": 18,
  "balance": 100.5,
  "vip": true,
  "extension": {
    "foo": "bar"
  }
}

클래스 인스턴스

webman은 매개변수 유형 제시를 통해 클래스 인스턴스를 전달하는 것을 지원합니다. 예를 들어,

app\service\Blog.php

<?php
namespace app\service;
class Blog
{
    private $title;
    private $content;
    public function __construct(string $title, string $content)
    {
        $this->title = $title;
        $this->content = $content;
    }
    public function get()
    {
        return [
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}

app\controller\BlogController.php

<?php
namespace app\controller;
use app\service\Blog;
use support\Response;

class BlogController
{
    public function create(Blog $blog): Response
    {
        return json($blog->get());
    }
}

/blog/create?blog[title]=hello&blog[content]=world에 접근하면 다음과 같은 결과를 얻습니다.

{
  "title": "hello",
  "content": "world"
}

모델 인스턴스

app\model\User.php

<?php
namespace app\model;
use support\Model;
class User extends Model
{
    protected $connection = 'mysql';
    protected $table = 'user';
    protected $primaryKey = 'id';
    public $timestamps = false;
    // 여기서 안전하지 않은 필드가 프론트엔드로 전달되는 것을 방지하기 위해 fillable 필드를 추가해야 합니다.
    protected $fillable = ['name', 'age'];
}

app\controller\UserController.php

<?php
namespace app\controller;
use app\model\User;
class UserController
{
    public function create(User $user): int
    {
        $user->save();
        return $user->id;
    }
}

/user/create?user[name]=tom&user[age]=18에 접근하면 유사한 결과를 얻습니다.

1

컨트롤러 생명 주기

config/app.php에서 controller_reusefalse로 설정되면, 각 요청마다 해당 컨트롤러 인스턴스가 초기화되고 요청이 끝난 후 컨트롤러 인스턴스는 소멸됩니다. 이는 전통적인 프레임워크의 실행 메커니즘과 같습니다.

config/app.php에서 controller_reusetrue로 설정되면, 모든 요청이 컨트롤러 인스턴스를 재사용합니다. 즉, 컨트롤러 인스턴스가 한 번 생성되면 메모리에 상주하여 모든 요청이 이 인스턴스를 재사용합니다.

주의
컨트롤러 재사용을 활성화할 경우 요청이 컨트롤러의 속성을 변경해서는 안 됩니다. 이러한 변경은 후속 요청에 영향을 줄 수 있습니다. 예를 들어,

<?php
namespace app\controller;

use support\Request;

class FooController
{
    protected $model;

    public function update(Request $request, $id)
    {
        $model = $this->getModel($id);
        $model->update();
        return response('ok');
    }

    public function delete(Request $request, $id)
    {
        $model = $this->getModel($id);
        $model->delete();
        return response('ok');
    }

    protected function getModel($id)
    {
        // 이 메서드는 첫 번째 요청 update?id=1이후 model을 보존합니다.
        // 만약 다시 delete?id=2로 요청할 경우, 1의 데이터가 삭제됩니다.
        if (!$this->model) {
            $this->model = Model::find($id);
        }
        return $this->model;
    }
}


컨트롤러의 __construct() 생성자에서 데이터를 반환해도 효과가 없습니다. 예를 들어,

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function __construct()
    {
        // 생성자에서 데이터를 반환해도 효과가 없습니다. 브라우저는 이 응답을 받지 않습니다.
        return response('hello'); 
    }
}

컨트롤러 미재사용과 재사용의 차이

차이점은 다음과 같습니다.

컨트롤러 미재사용

각 요청마다 새로운 컨트롤러 인스턴스를 생성하고 요청이 끝난 후 해당 인스턴스를 해제하며 메모리를 회수합니다. 미재사용 컨트롤러는 전통적인 프레임워크와 같으며 대부분의 개발자에게 익숙합니다. 컨트롤러의 생성과 소멸이 반복되기 때문에 성능은 약간 떨어질 수 있습니다(helloworld 성능 테스트에서 약 10% 차이, 비즈니스 로직이 포함된 경우 거의 무시할 수 있습니다).

컨트롤러 재사용

재사용할 경우 한 프로세스에서 컨트롤러를 한 번만 생성하며 요청 종료 후 이 컨트롤러 인스턴스를 해제하지 않습니다. 현재 프로세스의 후속 요청은 이 인스턴스를 재사용합니다. 재사용 컨트롤러는 성능이 더 좋지만 대부분의 개발자에게 익숙하지 않습니다.

다음 경우에는 컨트롤러 재사용을 사용할 수 없습니다.

컨트롤러의 속성을 변경할 때는 컨트롤러 재사용을 활성화할 수 없습니다. 이러한 속성 변경은 후속 요청에 영향을 미치기 때문입니다.

일부 개발자는 컨트롤러 생성자 __construct()에서 각 요청에 대한 초기화를 수행하는 것을 선호합니다. 이런 경우에는 컨트롤러를 재사용할 수 없습니다. 왜냐하면 현재 프로세스의 생성자는 한 번만 호출되므로 각 요청에 대해 호출되지 않기 때문입니다.