我目前正在考虑在我自己的MVC框架中使用反射类(主要是ReflectionClass和ReflectionMethod ),因为我需要自动实例化控制器类并调用它们的方法,而不需要任何必要的配置(“约定重于配置”方法)。
我担心性能,尽管我认为数据库请求可能比实际的PHP代码更大的瓶颈。
所以,我想知道是否有人从性能的角度对PHP5反射有好的或坏的体验。
此外,我很好奇是否有流行的PHP框架(CI、Cake、Symfony等)。实际使用反射。
发布于 2008-11-16 23:43:45
不要担心。安装Xdebug并确保瓶颈所在。
使用反射是有成本的,但这是否重要取决于您正在做什么。如果您使用反射实现控制器/请求分派器,则每个请求只使用一次。绝对可以忽略不计。
如果您使用反射实现您的ORM层,将它用于每个对象,甚至每个对属性的访问,并创建成百上千个对象,那么它的成本可能会很高。
发布于 2009-05-30 08:48:43
在我的机器上,调用一个静态函数一百万次将花费大约0.31秒。当使用ReflectionMethod时,大约需要1.82秒。这意味着使用反射API的成本要高出约500%。
顺便说一下,这是我使用的代码:
<?PHP
class test
{
static function f(){
return;
}
}
$s = microtime(true);
for ($i=0; $i<1000000; $i++)
{
test::f('x');
}
echo ($a=microtime(true) - $s)."\n";
$s = microtime(true);
for ($i=0; $i<1000000; $i++)
{
$rm = new ReflectionMethod('test', 'f');
$rm->invokeArgs(null, array('f'));
}
echo ($b=microtime(true) - $s)."\n";
echo 100/$a*$b;
显然,实际的影响取决于您期望执行的调用次数
发布于 2009-01-03 16:22:24
开销很小,所以不会有很大的性能损失,其他像数据库,模板处理等都是性能问题,用一个简单的动作测试你的框架,看看它有多快。
例如,下面的代码(frontcontroller)使用反射在几毫秒内就完成了工作
<?php
require_once('sanitize.inc');
/**
* MVC Controller
*
* This Class implements MVC Controller part
*
* @package MVC
* @subpackage Controller
*
*/
class Controller {
/**
* Standard Controller constructor
*/
static private $moduleName;
static private $actionName;
static private $params;
/**
* Don't allow construction of the controller (this is a singleton)
*
*/
private function __construct() {
}
/**
* Don't allow cloning of the controller (this is a singleton)
*
*/
private function __clone() {
}
/**
* Returns current module name
*
* @return string
*/
function getModuleName() {
return self :: $moduleName;
}
/**
* Returns current module name
*
* @return string
*/
function getActionName() {
return self :: $actionName;
}
/**
* Returns the subdomain of the request
*
* @return string
*/
function getSubdomain() {
return substr($_SERVER['HTTP_HOST'], 0, strpos($_SERVER['HTTP_HOST'], '.'));
}
function getParameters($moduleName = false, $actionName = false) {
if ($moduleName === false or ( $moduleName === self :: $moduleName and $actionName === self :: $actionName )) {
return self :: $params;
} else {
if ($actionName === false) {
return false;
} else {
@include_once ( FRAMEWORK_PATH . '/modules/' . $moduleName . '.php' );
$method = new ReflectionMethod('mod_' . $moduleName, $actionName);
foreach ($method->getParameters() as $parameter) {
$parameters[$parameter->getName()] = null;
}
return $parameters;
}
}
}
/**
* Redirect or direct to a action or default module action and parameters
* it has the ability to http redirect to the specified action
* internally used to direct to action
*
* @param string $moduleName
* @param string $actionName
* @param array $parameters
* @param bool $http_redirect
* @return bool
*/
function redirect($moduleName, $actionName, $parameters = null, $http_redirect = false) {
self :: $moduleName = $moduleName;
self :: $actionName = $actionName;
// We assume all will be ok
$ok = true;
@include_once ( PATH . '/modules/' . $moduleName . '.php' );
// We check if the module's class really exists
if (!class_exists('mod_' . $moduleName, false)) { // if the module does not exist route to module main
@include_once ( PATH . '/modules/main.php' );
$modClassName = 'mod_main';
$module = new $modClassName();
if (method_exists($module, $moduleName)) {
self :: $moduleName = 'main';
self :: $actionName = $moduleName;
//$_PARAMS = explode( '/' , $_SERVER['REQUEST_URI'] );
//unset($parameters[0]);
//$parameters = array_slice($_PARAMS, 1, -1);
$parameters = array_merge(array($actionName), $parameters); //add first parameter
} else {
$parameters = array($moduleName, $actionName) + $parameters;
$actionName = 'index';
$moduleName = 'main';
self :: $moduleName = $moduleName;
self :: $actionName = $actionName;
}
} else { //if the action does not exist route to action index
@include_once ( PATH . '/modules/' . $moduleName . '.php' );
$modClassName = 'mod_' . $moduleName;
$module = new $modClassName();
if (!method_exists($module, $actionName)) {
$parameters = array_merge(array($actionName), $parameters); //add first parameter
$actionName = 'index';
}
self :: $moduleName = $moduleName;
self :: $actionName = $actionName;
}
if (empty($module)) {
$modClassName = 'mod_' . self :: $moduleName;
$module = new $modClassName();
}
$method = new ReflectionMethod('mod_' . self :: $moduleName, self :: $actionName);
//sanitize and set method variables
if (is_array($parameters)) {
foreach ($method->getParameters() as $parameter) {
$param = current($parameters);
next($parameters);
if ($parameter->isDefaultValueAvailable()) {
if ($param !== false) {
self :: $params[$parameter->getName()] = sanitizeOne(urldecode(trim($param)), $parameter->getDefaultValue());
} else {
self :: $params[$parameter->getName()] = null;
}
} else {
if ($param !== false) {//check if variable is set, avoid notice
self :: $params[$parameter->getName()] = sanitizeOne(urldecode(trim($param)), 'str');
} else {
self :: $params[$parameter->getName()] = null;
}
}
}
} else {
foreach ($method->getParameters() as $parameter) {
self :: $params[$parameter->getName()] = null;
}
}
if ($http_redirect === false) {//no redirecting just call the action
if (is_array(self :: $params)) {
$method->invokeArgs($module, self :: $params);
} else {
$method->invoke($module);
}
} else {
//generate the link to action
if (is_array($parameters)) { // pass parameters
$link = '/' . $moduleName . '/' . $actionName . '/' . implode('/', self :: $params);
} else {
$link = '/' . $moduleName . '/' . $actionName;
}
//redirect browser
header('Location:' . $link);
//if the browser does not support redirecting then provide a link to the action
die('Your browser does not support redirect please click here <a href="' . $link . '">' . $link . '</a>');
}
return $ok;
}
/**
* Redirects to action contained within current module
*/
function redirectAction($actionName, $parameters) {
self :: $actionName = $actionName;
call_user_func_array(array(&$this, $actionName), $parameters);
}
public function module($moduleName) {
self :: redirect($moduleName, $actionName, $parameters, $http_redirect = false);
}
/**
* Processes the client's REQUEST_URI and handles module loading/unloading and action calling
*
* @return bool
*/
public function dispatch() {
if ($_SERVER['REQUEST_URI'][strlen($_SERVER['REQUEST_URI']) - 1] !== '/') {
$_SERVER['REQUEST_URI'] .= '/'; //add end slash for safety (if missing)
}
//$_SERVER['REQUEST_URI'] = @str_replace( BASE ,'', $_SERVER['REQUEST_URI']);
// We divide the request into 'module' and 'action' and save paramaters into $_PARAMS
if ($_SERVER['REQUEST_URI'] != '/') {
$_PARAMS = explode('/', $_SERVER['REQUEST_URI']);
$moduleName = $_PARAMS[1]; //get module name
$actionName = $_PARAMS[2]; //get action
unset($_PARAMS[count($_PARAMS) - 1]); //delete last
unset($_PARAMS[0]);
unset($_PARAMS[1]);
unset($_PARAMS[2]);
} else {
$_PARAMS = null;
}
if (empty($actionName)) {
$actionName = 'index'; //use default index action
}
if (empty($moduleName)) {
$moduleName = 'main'; //use default main module
}
/* if (isset($_PARAMS))
{
$_PARAMS = array_slice($_PARAMS, 3, -1);//delete action and module from array and pass only parameters
} */
return self :: redirect($moduleName, $actionName, $_PARAMS);
}
}
https://stackoverflow.com/questions/294582
复制相似问题