@lemonlimelike

Как вызывать метод без параметров, а сам метод сделать с параметрами?

Всем привет! Возможно мой вопрос туповат, но я не могу понять, как реализовано в laravel/symfony/yii такая штука, что когда делаешь объект какого-то класса, то можно не передавать ему параметры. А в самом классе конструктор может быть с параметрами. Так же самое и с методами.

Я подумал использовать ReflectionClass и его метод newInstanceWithoutConstructor, но тогда конструктор вообще не будет учитываться.

Как объявлять объект класса не учитывая параметры конструктора?

Скорее всего у меня неправильно реализована логика роутинга.

Вот мой класс Route.php
<?php

namespace Core;

use Core\Request;

class Route
{
	const FILE_ROUTES = BASE_DIR . "/config/routes.php";
	const DIR_SRC = BASE_DIR . "/App";

	private $routes;
	private $url;
	private $method;
	private $params;

	public function __construct(string $url, string $method)
	{
		$this->url = $url;
		$this->method = $method;
	}

	private function load()
	{
		if ( file_exists(self::FILE_ROUTES) ){
			$this->routes = require self::FILE_ROUTES;
		}else{
			throw new \Exception('Routes not found');
		}
		
	}

	private function existUrl(): ?array
	{
		$url = trim($this->url, '/');

		foreach($this->routes as $route){
			$route['url'] = rtrim($route['url'], "/");
			$regExp = "#^{$route['url']}$#";

			if ( preg_match($regExp, $url, $matches) and $route['method'] === $this->method ){
				$this->params = array_slice($matches,1);
				return $route;
			}
		}

		return Null;
	}

	public function run()
	{
		$this->load();

		$route = $this->existUrl();
		if ( !is_null($route) ){
			$pathController = self::DIR_SRC . "/Controller/" . $route['controller'];
			if (!file_exists($pathController)){
				throw new \Exception("File {$route['controller']} is not found");
			}else{
				require_once $pathController;
			}

			$path = trim("App\Controller\\".$route['controller'], ".php");

			if ( !class_exists($path) ){
				throw new \Exception("Class {$route['controller']} is not found");
			}

			$action = $route['action'];
			if ( !method_exists($path, $action) ){
				throw new \Exception("Method $action in class {$route['controller']} is not found");
			}


			$method = strtolower($route['method']);
			$this->$method($path, $route, $action);
		}
	}

	public function get(string $path, array $route, string $action)
	{
		$request = new Request();

		foreach ($this->params as $key => $value) {
			preg_match("/\d+/", $value, $match);
			if(!empty($match)){
				$id = intval($match[0]);
			}

			if (is_string($value)) {
				$request->name = $value;
			}
			if (is_int($id)){
				$request->id = $id;
			}
		}

		$args = [$request, ...$this->params];

		$controller = new $path;
		$controller($route);
		// $test = new \ReflectionClass($path);
		
		// // var_dump($reflection->getConstructor());
		// $controller = $test->newInstanceWithoutConstructor();
		// // $controller = $test->newInstance();
		// // $controller($route);
		// // var_dump($reflection);
		// $reflection = new \ReflectionMethod($controller, $action);
		// $reflection->invoke($controller, $args);
		call_user_func_array([$controller, $action], $args);
	}

	public function post(string $path, array $route, string $action)
	{
		$request = new Request();

		foreach ($_REQUEST as $key => $value) {
			$value = htmlspecialchars(trim($value), ENT_QUOTES);
			$request->$key = $value;
		}

		$args = [$request, ...$this->params];

		$controller = new $path($route);
		call_user_func_array([$controller, $action], $args);
	}
}


И вот как я его вызываю:
Файл index.php
use Core\Route;

spl_autoload_register(function ($class) {
    $path = str_replace("\\", "/", "$class.php");
	
    if(file_exists($path)){
    	require $path;
    }
});


$url = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];

$route = new Route($url, $method);
$route->run();


То есть я беру из _SERVER нужные данные дляя того, чтобы проверить если рут найден, если найден, то вызываю соотвествующий ему метод (GET | POST), и делаю объект контроллера, который соотвествует этому руту и вызываю метод для этого рута.

А вот как у меня выглядит IndexController

<?php

namespace App\Controller;

use Core\Controller;
use Core\Request;
use App\Entity\Action;
use App\Repository\ActionRepository;

class IndexController extends Controller
{
	private $actionRepository;

	public function __construct(ActionRepository $actionRepository)
	{
		$this->actionRepository = $actionRepository;
		var_dump("expression");
	}
	
	public function index()
	{

		$action = new Action();
		$action->prenumeAction = "Test";
		$action->nrTelefonAction = "123213";

		var_dump($this->actionRepository);

		$data = [
			'title' => "Title"
		];
		return $this->render("home.index", $data);
	}	
}


Как видно в этом IndexController у меня конструктор принимает параметр, а в Route я делаю экземпляр класса без этого параметра. И происходит ошибка соответсвенно. Как добиться такого, чтоб можно было делать объект класса без параметра?
  • Вопрос задан
  • 132 просмотра
Решения вопроса 1
hrabry
@hrabry
Как добиться такого, чтоб можно было делать объект класса без параметра?

когда делаешь объект какого-то класса, то можно не передавать ему параметры. А в самом классе конструктор может быть с параметрами

class MyClass {
    
    public $param;
    public $actionRepository;
    
    public function __construct(?ActionRepository $actionRepository = null, $param= null)
    {
        $this->actionRepository = $actionRepository;
        $this->param = $param;
    }
}


$myClass = new MyClass();
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@rPman
после 5.6 версии php можно использовать variadic functions
function test(...$params){var_dump($params);}
test(1,2,3);

работает для всех мест использования - функций, методов, замыканий.
Ответ написан
Комментировать
Jakim
@Jakim
Laravel - developer
Возможно что-то не правильно понял, НО!

$route = new Route($url, $method); // тут по сути произошло new IndexController
$route->run(); // здесь соответственно вызывается функция run по типу (new IndexController)->run()


но ведь самой функции run в контроллере нет.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы