The arguments don't magically "move". When you do this, laravel takes the path/function combination and stores them for later. This is a simplified version of what happens:
class Route
{
private static $GET = array();
public static function get($path, $callback)
{
self::$GET[] = array($path, $callback);
}
}
Then later, after all the routes are added, it checks what URL the webpage was called with, and finds the path that matches it. There is some internal procedure that takes the $path for each route and converts it to a regular expression like #user/(?P<id>.+)#, so matching is just done with something like preg_match(). Upon a successful hit, it stops and extracts the variables:
'/user/foobar' has the username extracted: array('id' => 'foobar')
It then uses reflection to match the parameters in the callback with the data from the URL.
$callback_reflection = new ReflectionFunction($callback);
$arguments = $callback_reflection->getParameters();
/* some algorithm to match the data and store in $args */
$result = $callback_reflection->invokeArgs($args);
The invokeArgs() method is what would execute your callback with the correct arguments. There isn't really much magic here. See the Router class for more details.