Router for personal use
You need to decide on the Domain Objects that represent concepts in your current model.

A Route object should encapsulate the data to do with a route. If you look at Symfony's Route you'll see that it is simply an object with some properties, getters and setters, and that's about it (apart from a few select helper functions). This is also known as an Entity, the end object that you get back.

So, now you know that you want to get back some Route entities (@return Route[] in phpdoc), you should:


Create a Route object which merely represents a route
Take a look at the Factory Pattern and create a factory for these


The object API I would then expect to be using would be:

$router = new Router(new RouteFactory);
/** @var Route $route */
$route = $router-&gt;createRoute('/', 'PageController', 'showHome');


Somewhere in the Router, it would call RouteFactory::create($param1, $param2 ...) to actually make a Route object.

Don't expect the user to remember to call createRoute() followed by runRoute(). If one can't be run before the other, then it looks like you're trying to implement the builder creational pattern (which is for optional parameters). Your createRoute() method should return a Route object.

In the context of routing itself, you'll likely want something called a Resolver. That is, something you pass a Route to, and it instantiates the thing you are routing to. In an 'MVC' framework, you have a ControllerResolver - so you would create a Route, call ControllerResolver::resolve(Route $route) and that would contain the logic to decide what controller to create based on the contents of the Route object (so it'd do things like class_exists($controllerName) etc.

It looks like you're trying to design some generic router, but it is doing too many things. Focus on making the following seperately:


An object representing your route (Route)
An object responsible for creating a route from $_POST etc (RouteFactory::createFromGlobals($_POST) (or similar))
An object responsible for taking your Route and doing what you want to do with it (ControllerResolver (or similar))


Separate the actions out that you want to do, contextually, and you'll achieve better SoC.

Also, you shouldn't be accessing any superglobals ($_*) within this class, you should pass them in instead. This means that during testing you fake (or 'mock') the data you pass in with relative ease and test that your object still functions as you expect over different scenarios.