php 在类的方法中如何获取调用该方法的方法名称?

在编写一个简单的MVC 框架 demo 时遇到一个问题,就是在控制器的方法中调用父类的一个显示模板的函数,调用方式有两种:

  
$this -> showTpl('tpl_name'); //指定模板名称
$this -> showTpl(); //不指定模板名称

如果不指定模板名称的话,会根据当前的 Controller 和 action 加载模板,想让使用更加方便,例:

  
class IndexController extends Core_Controller{

<coding-1 lang="other">

public function __construct() {

parent::__construct();

}
public function testAction() {

$this -> showTpl();

}

那么他将引入的是 index_test.html 页面,(这种命名方式的好处就是可以根据模板直接找到使用该模板的Controller和action); 问题是 如何在 Core_Controller 中的showTpl() 方法中 取到 调用它的方法?

类的话到好说在showTpl() 方法中直接 get_class($this); 得到调用该方法的类,
但是方法名称如何获取?目前使用 debug_backtrace() 函数勉强获得,不知道大家有没有什么简单的方式获得?

崔苔吾
崔苔吾
7597
编辑于2012-03-03
评论 (1)链接2012-02-18 
  • 0 支持
    这问题不错哇,期待答案中... – 崔苔吾 2012-02-18
  
<?php
// filename: /tmp/a.php

function a_test($str)
{
echo "\nHi: $str";
var_dump(debug_backtrace());
}

a_test('friend');
?>

<?php
// filename: /tmp/b.php
include_once '/tmp/a.php';
?>

来自:http://s.yanghao.org/program/viewdetail.php?i=7150

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (1)链接 • 2012-02-18
  • 0 支持
    虽然和我的方法一样,但是你的这个答案还是最靠谱的。 – 冯义军 2012-02-24

我现在有一个框架很符合你的需求.
1.页面链接大概是index.php?act=goods.main,在index.php页面会获取act参数,通过list($ctrl,$fun)=explode(',',$_GET['act']);
2.$m=new goods($ctrl,$fun);你在Core_Controller类里定义两个变量ctrl和fun,定义Core_Controller的构造函数时作如下操作,$this->ctrl=$ctrl;$this->fun=$fun;
3,在 showTpl方法中就可得到模板文件名了,$this->tpl=$this->ctrl.'.'$this->fun.'.html';
4.在goods类里你就直接调用showTpl方法,不用再传模板文件名了。

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (4)链接 • 2012-02-18
  • 0 支持
    我最开始的的写法就像你说的这样,通过请求来实现地址,但是存在一个问题比如访问:
    index.php/index/test/2
    那么index控制器中的方法test方法如下:
    public function test() {
    $args = $this -> getArgs();
    switch($args[0]) {
    case 1 : $this -> one(); break;
    case 2 : $this -> two();break;
    ……
    }
    }
    如果根据url来获取模板的话那么就是 index_test.html了,但是根据实际的情况,应该是 index_tow.html
    – 冯义军 2012-02-18
  • 0 支持
    你可以在调用one()或two()时修改$this->fun; – 董琛 2012-02-18
  • 0 支持
    在开发者自己的建立的 Controller 怎么写,我控制不了啊。 – 冯义军 2012-02-18
  • 0 支持
    我觉得mvc应该是一个行为一个方法。 – 董琛 2012-02-19

我很赞同@董琛的方法,其实你也可以在每个方法里传个当前方法的名过去,例如:

  
public function testAction() {
$this -> showTpl(__FUNCTION__);
}

再者,Core_Controller里的showTpl既然可以接收模板文件名,你只是想根据模板名来知道该行为是执行的那个类那个方法,为何不直接传个模板名呢?例如:two()里直接$this -> showTpl(‘index_two’);这样的话作为新开发者更容易理解你的框架。纯属个人建议!

小飞
小飞
6842
编辑于 2012-03-02
该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0)链接 • 2012-02-19

发一个我用的类

  
/**
* 动作对象基础类
*/
abstract class MvcBaseAction
{
/**
* 应用程序对象
*
* @var MvcAppEntry
*/
public $app;

/**
* 动作名称
*
* @var string
*/
public $name;

/**
* 当前请求
*
* @var MvcRequest
*/
public $request;

/**
* 执行结果
*
* @var mixed
*/
public $result;

/**
* 构造函数
*
* @param MvcAppEntry $app
* @param string $name
*/
function __construct(MvcAppEntry $app, $name)
{
$this->app = $app;
$this->name = $name;
$this->request = $app->request;
}

/**
* UDI 转 MVC Action 标识
*/
static function parseUDI(array $udi){
// 剔除掉 :module
if ($udi[Router::operate] != Router::default_operate){
return sprintf('%s.%s',$udi[Router::operate],$udi[Router::action]);
}
return $udi[Router::action];
}
/**
* 执行动作
*/
function __execute()
{
if (!$this->__before_execute()) return;
if ($this->validate_input())
{
$result = $this->execute();
if (!is_null($result)) $this->result = $result;
if (!$this->validate_output())
{
$this->on_validate_output_failed();
}
}
else
{
$this->on_validate_input_failed();
}
$this->__after_execute();
}

/**
* 执行指定的视图对象
*
* @param array $vars
* @param string $viewname
*/
function view(array $vars = null,$viewname=null)
{
if (!is_array($vars)) $vars = array();
$this->result = $this->app->view($viewname ? $viewname : $this->name, $vars);
}

/**
* 应用程序执行的动作内容,在继承的动作对象中必须实现此方法
*
* 返回值会被保存到动作对象的 $result 属性中。
*
* @return mixed
*/
abstract function execute();

/**
* 继承类覆盖此方法,用于在执行请求前过滤并验证输入数据
*
* 如果返回 false 则阻止调用 execute() 方法,并调用 validate_input_failed() 方法。
*
* @return bool
*/
function validate_input()
{
return true;
}

/**
* 继承类覆盖此方法,用于在执行请求后过滤并验证输出数据
*
* 如果返回 false 则调用 validate_output_failed() 方法。
*
* @return bool
*/
function validate_output()
{
return true;
}

/**
* 请求前对数据进行验证失败时调用此方法
*/
function on_validate_input_failed()
{
}

/**
* 请求执行后对数据进行验证失败时调用此方法
*/
function on_validate_output_failed()
{
}

/**
* 执行动作之前调用,如果返回 false 则阻止动作的执行
*
* @return bool
*/
protected function __before_execute()
{
return true;
}

/**
* 执行动作之后调用
*/
protected function __after_execute()
{
}
}

上述是 action 的基类,在分发器处可以如此调用,把action名称传进去,视图文件默认就使用传入的action的名字

  
/**
* 执行应用程序
*
* @param string $action_name 这个应该是 将 udi 转换之后的名称
*
* @return mixed
*/
function run($action_name = null)
{
// 解析请求 URL 中的动作名称
if (is_null($action_name))
{
$action_name = $this->config->get('app.defentry');
}
$action_name = self::_format_action_name($action_name);

// 动作对象
$action_class_name = str_replace('.', '_', $action_name) . 'Action';
$action_class_file = $this->_base_path . '/actions/' . str_replace('.', '/', $action_name) . '.php';
CoreApp::import($action_class_file,null,true);

if (!class_exists($action_class_name,false))
{
return $this->_process_result($this->_on_action_not_found($action_class_name));
}

// 执行动作
$action = new $action_class_name($this, $action_name);
/* @var $action MvcBaseAction */
$action->__execute();
return $this->_process_result($action->result);
}
小飞
小飞
6842
编辑于 2012-03-02
该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0)链接 • 2012-02-19

一个类只提供一个action标准方法,完全从类名中解析模板,也可结合一级或多级命名空间。

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0)链接 • 2012-03-07
德问是一个专业的编程问答社区,请 登录注册 后再提交答案