• Laravel controller分析


    <?php namespace Laravel\Routing;
    
    use Laravel\IoC;
    use Laravel\Str;
    use Laravel\View;
    use Laravel\Event;
    use Laravel\Bundle;
    use Laravel\Request;
    use Laravel\Redirect;
    use Laravel\Response;
    use FilesystemIterator as fIterator;
    
    abstract class Controller {
    
    	/**
    	 * 控制器布局
    	 *
    	 * @var string
    	 */
    	public $layout;
    
    	/**
    	 * 控制器属于的软件包
    	 *
    	 * @var string
    	 */
    	public $bundle;
    
    	/**
    	 * RESTful控制器标记
    	 *
    	 * @var bool
    	 */
    	public $restful = false;
    
    	/**
    	 * 控制器的过滤器
    	 *
    	 * @var array
    	 */
    	protected $filters = array();
    
    	/**
    	 * 控制器工厂的事件名称
    	 *
    	 * @var string
    	 */
    	const factory = 'laravel.controller.factory';
    
    	/**
    	 * 构造
    	 *
    	 * @return void
    	 */
    	public function __construct()
    	{
    		// If the controller has specified a layout to be used when rendering
    		// views, we will instantiate the layout instance and set it to the
    		// layout property, replacing the string layout name.
    		if ( ! is_null($this->layout))
    		{
    			$this->layout = $this->layout();
    		}
    	}
    
    	/**
    	 * 给定软件包检测所有控制器
    	 *
    	 * @param  string  $bundle
    	 * @param  string  $directory
    	 * @return array
    	 */
    	public static function detect($bundle = DEFAULT_BUNDLE, $directory = null)
    	{
    		if (is_null($directory))
    		{
    			$directory = Bundle::path($bundle).'controllers';# 寻找软件包的控制器目录
    		}
    
    		// First we'll get the root path to the directory housing all of
    		// the bundle's controllers. This will be used later to figure
    		// out the identifiers needed for the found controllers.
    		$root = Bundle::path($bundle).'controllers'.DS; # 解析根目录
    
    		$controllers = array();
    
    		$items = new fIterator($directory, fIterator::SKIP_DOTS); # 把目录包装成对象
    
    		foreach ($items as $item)
    		{
    			// If the item is a directory, we will recurse back into the function
    			// to detect all of the nested controllers and we will keep adding
    			// them into the array of controllers for the bundle.
    			if ($item->isDir()) # 如果是目录就递归
    			{
    				$nested = static::detect($bundle, $item->getRealPath());
    
    				$controllers = array_merge($controllers, $nested); # 结果是组成的数组
    			}
    
    			// If the item is a file, we'll assume it is a controller and we
    			// will build the identifier string for the controller that we
    			// can pass into the route's controller method.
    			else
    			{
    				$controller = str_replace(array($root, EXT), '', $item->getRealPath());
    
    				$controller = str_replace(DS, '.', $controller);
    
    				$controllers[] = Bundle::identifier($bundle, $controller); # 文件就假设它是控制器并且传递到路由器中
    			}
    		}
    
    		return $controllers;
    	}
    
    	/**
    	 * 调用控制器方法
    	 *
    	 * <code>
    	 *		// 控制器名称@方法名称
    	 *		$response = Controller::call('user@show');
    	 *
    	 *		// 二级目录名称。控制器名称@方法名称,参数数组
    	 *		$response = Controller::call('user.admin@profile', array($username));
    	 * </code>
    	 *
    	 * @param  string    $destination
    	 * @param  array     $parameters
    	 * @return Response
    	 */
    	public static function call($destination, $parameters = array())
    	{
    		static::references($destination, $parameters);
    
    		list($bundle, $destination) = Bundle::parse($destination);# 软件包解析 解析的目的是为了找到相应的目录
    
    		// We will always start the bundle, just in case the developer is pointing
    		// a route to another bundle. This allows us to lazy load the bundle and
    		// improve speed since the bundle is not loaded on every request.
    		Bundle::start($bundle); # 延迟加载软件包
    
    		list($name, $method) = explode('@', $destination);# 解析出方法和名称
    
    		$controller = static::resolve($bundle, $name);
    
    		// For convenience we will set the current controller and action on the
    		// Request's route instance so they can be easily accessed from the
    		// application. This is sometimes useful for dynamic situations.
    		if ( ! is_null($route = Request::route()))
    		{
    			$route->controller = $name;
    
    			$route->controller_action = $method;
    		}
    
    		// If the controller could not be resolved, we're out of options and
    		// will return the 404 error response. If we found the controller,
    		// we can execute the requested method on the instance.
    		if (is_null($controller)) # 找不到
    		{
    			return Event::first('404');
    		}
    
    		return $controller->execute($method, $parameters);
    	}
    
    	/**
    	 * Replace all back-references on the given destination.
    	 *
    	 * @param  string  $destination
    	 * @param  array   $parameters
    	 * @return array
    	 */
    	protected static function references(&$destination, &$parameters)
    	{
    		// Controller delegates may use back-references to the action parameters,
    		// which allows the developer to setup more flexible routes to various
    		// controllers with much less code than would be usual.
    		foreach ($parameters as $key => $value)
    		{
    			if ( ! is_string($value)) continue;
    
    			$search = '(:'.($key + 1).')';
    
    			$destination = str_replace($search, $value, $destination, $count);# 处理字符串 可能是某种特殊的用法
    
    			if ($count > 0) unset($parameters[$key]);
    		}
    
    		return array($destination, $parameters);
    	}
    
    	/**
    	 * 解析软件包和控制器
    	 *
    	 * @param  string      $bundle
    	 * @param  string      $controller
    	 * @return Controller
    	 */
    	public static function resolve($bundle, $controller)
    	{
    		if ( ! static::load($bundle, $controller)) return;
    
    		$identifier = Bundle::identifier($bundle, $controller);
    
    		// If the controller is registered in the IoC container, we will resolve
    		// it out of the container. Using constructor injection on controllers
    		// via the container allows more flexible applications.
    		$resolver = 'controller: '.$identifier;
    
    		if (IoC::registered($resolver))
    		{
    			return IoC::resolve($resolver); # 从容器中返回控制器
    		}
    
    		$controller = static::format($bundle, $controller);
    
    		// If we couldn't resolve the controller out of the IoC container we'll
    		// format the controller name into its proper class name and load it
    		// by convention out of the bundle's controller directory.
    		if (Event::listeners(static::factory))
    		{
    			return Event::first(static::factory, $controller);
    		}
    		else
    		{
    			return new $controller;
    		}
    	}
    
    	/**
    	 * 加载控制文件
    	 *
    	 * @param  string  $bundle
    	 * @param  string  $controller
    	 * @return bool
    	 */
    	protected static function load($bundle, $controller) # 加载控制器文件
    	{
    		$controller = strtolower(str_replace('.', '/', $controller));
    
    		if (file_exists($path = Bundle::path($bundle).'controllers/'.$controller.EXT))
    		{
    			require_once $path;
    
    			return true;
    		}
    
    		return false;
    	}
    
    	/**
    	 * 格式化类名
    	 *
    	 * @param  string  $bundle
    	 * @param  string  $controller
    	 * @return string
    	 */
    	protected static function format($bundle, $controller)
    	{
    		return Bundle::class_prefix($bundle).Str::classify($controller).'_Controller';
    	}
    
    	/**
    	 * 控制器方法获得参数
    	 *
    	 * @param  string    $method
    	 * @param  array     $parameters
    	 * @return Response
    	 */
    	public function execute($method, $parameters = array())
    	{
    		$filters = $this->filters('before', $method);
    
    		// Again, as was the case with route closures, if the controller "before"
    		// filters return a response, it will be considered the response to the
    		// request and the controller method will not be used.
    		$response = Filter::run($filters, array(), true);
    
    		if (is_null($response))
    		{
    			$this->before();
    
    			$response = $this->response($method, $parameters);
    		}
    
    		$response = Response::prepare($response);
    
    		// The "after" function on the controller is simply a convenient hook
    		// so the developer can work on the response before it's returned to
    		// the browser. This is useful for templating, etc.
    		$this->after($response);
    
    		Filter::run($this->filters('after', $method), array($response));
    
    		return $response;
    	}
    
    	/**
    	 * Execute a controller action and return the response.
    	 *
    	 * Unlike the "execute" method, no filters will be run and the response
    	 * from the controller action will not be changed in any way before it
    	 * is returned to the consumer.
    	 *
    	 * @param  string  $method
    	 * @param  array   $parameters
    	 * @return mixed
    	 */
    	public function response($method, $parameters = array())
    	{
    		// The developer may mark the controller as being "RESTful" which
    		// indicates that the controller actions are prefixed with the
    		// HTTP verb they respond to rather than the word "action".
    		if ($this->restful)
    		{
    			$action = strtolower(Request::method()).'_'.$method;
    		}
    		else
    		{
    			$action = "action_{$method}";
    		}
    
    		$response = call_user_func_array(array($this, $action), $parameters);
    
    		// If the controller has specified a layout view the response
    		// returned by the controller method will be bound to that
    		// view and the layout will be considered the response.
    		if (is_null($response) and ! is_null($this->layout))
    		{
    			$response = $this->layout;
    		}
    
    		return $response;
    	}
    
    	/**
    	 * 注册过滤器
    	 *
    	 * <code>
    	 *		// Set a "foo" after filter on the controller
    	 *		$this->filter('before', 'foo');
    	 *
    	 *		// Set several filters on an explicit group of methods
    	 *		$this->filter('after', 'foo|bar')->only(array('user', 'profile'));
    	 * </code>
    	 *
    	 * @param  string             $event
    	 * @param  string|array       $filters
    	 * @param  mixed              $parameters
    	 * @return Filter_Collection
    	 */
    	protected function filter($event, $filters, $parameters = null)
    	{
    		$this->filters[$event][] = new Filter_Collection($filters, $parameters); # 过多的对象都是利用array基本的数据结构构造的
    
    		return $this->filters[$event][count($this->filters[$event]) - 1];
    	}
    
    	/**
    	 * Get an array of filter names defined for the destination.
    	 *
    	 * @param  string  $event
    	 * @param  string  $method
    	 * @return array
    	 */
    	protected function filters($event, $method)
    	{
    		if ( ! isset($this->filters[$event])) return array();
    
    		$filters = array();
    
    		foreach ($this->filters[$event] as $collection)
    		{
    			if ($collection->applies($method))
    			{
    				$filters[] = $collection;
    			}
    		}
    
    		return $filters;
    	}
    
    	/**
    	 * 控制器布局
    	 *
    	 * @return View
    	 */
    	public function layout()
    	{
    		if (starts_with($this->layout, 'name: '))
    		{
    			return View::of(substr($this->layout, 6));
    		}
    
    		return View::make($this->layout);
    	}
    
    	/**
    	 * 动作之前
    	 *
    	 * @return void
    	 */
    	public function before() {}
    
    	/**
    	 * 动作之后 值得注意是传入了$response结果
    	 *
    	 * @param  Response  $response
    	 * @return void
    	 */
    	public function after($response) {}
    
    	/**
    	 * Magic Method to handle calls to undefined controller functions.
    	 */
    	public function __call($method, $parameters)
    	{
    		return Response::error('404');
    	}
    
    	/**
    	 * 动态过滤器
    	 *
    	 * <code>
    	 *		// Retrieve an object registered in the container
    	 *		$mailer = $this->mailer;
    	 *
    	 *		// Equivalent call using the IoC container instance
    	 *		$mailer = IoC::resolve('mailer');
    	 * </code>
    	 */
    	public function __get($key)
    	{
    		if (IoC::registered($key))
    		{
    			return IoC::resolve($key);
    		}
    	}
    
    }
    

    底层的控制器提供的功能 

  • 相关阅读:
    机器学习——EM算法
    机器学习——贝叶斯分类器
    机器学习——朴素贝叶斯法
    论文解读(SimCLR)《A Simple Framework for Contrastive Learning of Visual Representations》
    机器学习——数据增强
    机器学习——正则化方法Dropout
    ResNet
    机器学习——最小二乘法
    机器学习——K-Means算法
    机器学*——K*邻算法(KNN)
  • 原文地址:https://www.cnblogs.com/snakevash/p/3046945.html
Copyright © 2020-2023  润新知