php调用类中属性和函数的常用方法->_=>_::_$this->

在php中有同学经常搞不明白->,=>,::,$this->的作用,下面通过例子讲解下。

 

一、->用来引用一个类的属性(变量)、方法(函数)

 

可以把->理解成调用的意思

如:

<?php

Class a{

Var $id;

Function add(){

$this->id=”test”;

echo “abc”;

}

}

$b = new a;

$b->add();  //调用类a中的add()方法,输出为abc

Echo $b->id; //调用类a中的属性id,输出为test

?>

二、=>是用来定义数组用的

 

=>用来定义数组的,比如:

$arr1 =array(0=>'php',1=>'is',the=>'the');

Echo $arra[0],$arr1[1],$arr[‘the’];   //对应输出设置的值

 

三、::用来直接调用类中的属性或方法

 

正常的情况我们用实例化方法来调用类中的属性或方法,但使用::可以不需要实例化对象,直接调用即可。比如:

 

Class b{

Var $name=”test”;

 

Function Getname(){

Echo “test is good”;

}

}

直接调用:

Echo b::Getname();//输出为test isgood

 

 

 

 

四、$this->表示实例化后的具体对象

 

我们一般在一个类的内部使用本类的属性或方法时,就使用$this->

如:

Class a{

Var $name;

 

Function Getname(){

Echo $this->name;

}

}

$name1 = new a;

$name1->name = “赋值给name”;

$name1->Getname(); //调用函数,并且输出为 “赋值给name”

 

通过例子大家应该明白这几个的用法了,可以加QQ群交流610845268

我第一个问题中,我的base是这样的: <?php /** * 自定义Controller基,所有Controller必须继承 * 同时,子必须实现_init函数 * */ abstract class Kepler_Controller_Base extends Yaf_Controller_Abstract{ //输入参数 protected $_arrInput = array(); //结果数组 protected $_arrResult = array(); //是否需要授权 protected $_authFlag = true; //是否需要IP限制 protected $_ipFlag = false; //子初始化函数,强制子实现 abstract public function _init(); /* * 禁止子重写覆盖init方法 * 在这里初始化一些基本信息 */ final public function init(){ $this->_arrInput = Kepler_Http::Input(); $this->_arrResult = Kepler_Result::Original(); var_dump(class_exists('Yaf_Controller_Abstract')); // 应输出 true var_dump(new ReflectionClass('Yaf_Controller_Abstract')); // 查看定义位置 var_dump(1); var_dump($this->_authFlag); //先执行初始化函数 $this->_init(); var_dump(4); var_dump($this->_authFlag); die; //再执行钩子 $this->beforeHook(); } /* * 执行action之前钩子 * 比如:校验权限、校验IP等等 */ public function beforeHook() { $this->checkAuth(); $this->checkIp(); } 我的接口是这样的: <?php class UserController extends Kepler_Controller_Base { // 在构造函数中设置(优先于 init() 执行) public function __construct($request, $response, $view) { parent::__construct($request, $response, $view); $this->_authFlag = false; // 提前设置 } public function _init() { var_dump(2); var_dump($this->_authFlag); //不用校验登陆 $this->_authFlag = false; var_dump(3); var_dump($this->_authFlag); } //登陆提交 public function loginpostAction(){ $model = new User_Service_LoginPost(); $this->_arrResult = $model->execute(); } 但是我请求这个loginpostAction接口时,代码只走了base,根本就不会走接口中的public function _init() { var_dump(2); var_dump($this->_authFlag); //不用校验登陆 $this->_authFlag = false; var_dump(3); var_dump($this->_authFlag); }
最新发布
07-24
<think>我们正在分析Yaf框架中控制器初始化方法调用的问题。用户描述的场景是:在自定义基Kepler_Controller_Base中,init方法调用了抽象方法_init,但子UserController中实现的_init方法在请求时没有被执行。我们需要找出原因并提供解决方案。 首先,回顾Yaf控制器的生命周期: 1. 当请求到达时,Yaf会实例化对应的控制器(如UserController)。 2. 在控制器实例化后,Yaf会自动调用该控制器的init方法(如果存在)。 在用户描述的代码结构中: - Kepler_Controller_Base 继承自 Yaf_Controller_Abstract。 - Kepler_Controller_Base 是一个抽象,它包含一个抽象方法 _init。 - Kepler_Controller_Base 的 init 方法(非抽象)中调用$this->_init()。 - UserController 继承自 Kepler_Controller_Base,并实现了 _init 方法。 根据上述结构,预期的行为是: 1. 当UserController被实例化后,Yaf会调用其init方法(因为UserController没有覆盖init方法,所以会调用Kepler_Controller_Base的init方法)。 2.的init方法调用$this->_init(),由于$this是UserController的实例,因此应该调用UserController的_init方法。 但用户观察到_init方法没有被执行,可能的原因有: **原因一:Yaf框架的控制器初始化方法命名规范** Yaf框架中,控制器的初始化方法应该是`init`,而不是`_init`。在Yaf的控制器中,如果存在`init`方法,它会在控制器实例化后自动调用。但是,如果基中已经定义了`init`方法,而子没有覆盖,那么基的`init`方法会被执行。然而,这里用户将抽象方法命名为`_init`(带下划线),而基的`init`方法(不带下划线)调用了`_init`。 问题可能在于:用户可能错误地覆盖了Yaf的初始化方法。Yaf期望的初始化方法是`init`,而用户自定义了一个`_init`方法,但Yaf并不会自动调用`_init`。因此,只有基的`init`方法被Yaf调用,而基的`init`方法调用了`_init`,所以子的`_init`应该被调用。但用户说没有执行,所以我们需要考虑其他原因。 **原因二:子未正确实现抽象方法** 如果子UserController没有实现抽象方法`_init`,那么会导致编译错误(无法实例化抽象)。但用户描述中已经说明子实现了,所以这个原因可以排除。 **原因三:方法可见性** 在PHP中,子实现抽象方法时,方法的可见性不能比抽象方法更严格。抽象方法`_init`在基中可能是`protected`或`public`(抽象中的抽象方法不能是private)。子实现时,必须使用相同或更宽松的可见性。如果子将`_init`方法定义为`private`,则会导致调用失败。但通常我们使用`protected`或`public`,所以需要检查子方法的可见性。 **原因四:自动加载问题** 如果子UserController的文件没有被正确加载,那么当基调用`$this->_init()`时,由于子尚未被定义,可能无法找到子的`_init`方法。但根据问题描述,控制器已经被实例化,说明UserController已经被加载,所以这个可能性较低。 **原因五:Yaf的控制器初始化流程覆盖** Yaf在实例化控制器后,只会调用`init`方法(不带下划线)。如果用户在基中定义了`init`方法,并且在该方法调用`_init`,那么只要子正确实现了`_init`,就应该被调用。所以,我们需要检查基中`init`方法的实现中`_init`方法的实现。 **可能的问题代码:** 基Kepler_Controller_Base可能如下: ```php abstract class Kepler_Controller_Base extends Yaf_Controller_Abstract { public function init() { // 调用实现的初始化方法 $this->_init(); } abstract protected function _init(); } ``` 子UserController可能如下: ```php class UserController extends Kepler_Controller_Base { protected function _init() { // 初始化代码 echo "UserController _init called"; } public function indexAction() { // 动作 } } ``` 按照上述代码,当访问UserController的indexAction时,基的init方法会被调用,然后调用的_init方法。所以,理论上应该输出"UserController _init called"。 如果用户没有看到输出,可能的原因有: 1.的`_init`方法被错误地定义为私有(private)?但上面例子是protected,符合要求。 2.中可能意外覆盖了`init`方法?如果子覆盖了`init`方法,但没有调用`parent::init()`,那么基的`init`方法就不会执行,也就不会调用`_init`。例如: ```php class UserController extends Kepler_Controller_Base { public function init() { // 覆盖了基的init方法,但没有调用的init // 所以基的init不会执行,_init也不会被调用 } protected function _init() { // 不会被执行 } } ``` **解决方案:** 1. 检查子UserController是否覆盖了`init`方法。如果覆盖了,确保在子的`init`方法调用`parent::init()`。 2. 确保子的`_init`方法可见性正确(至少为protected,不能是private)。 3. 检查基Kepler_Controller_Base中`init`方法的可见性。在Yaf中,控制器的init方法必须是public,因为Yaf框架在外部调用它。所以基的init方法应该是public。 **总结:** 最可能的原因是子覆盖了`init`方法但没有调用的`init`方法,导致基的`init`方法没有执行,进而没有调用`_init`。因此,需要检查子中是否有`init`方法,如果有,必须调用`parent::init()`。 如果子没有覆盖`init`方法,那么问题可能出在其他地方,比如文件路径错误导致子文件未正确加载(但控制器能实例化说明文件已加载),或者有语法错误导致方法不可用。 建议用户检查子UserController的代码,确保没有意外覆盖`init`方法,或者如果覆盖了,必须调用的`init`。 另外,为了调试,可以在基的`init`方法中添加日志,确认是否被调用;在子的`_init`方法中也添加日志,确认是否被调用。这样可以帮助定位问题。 **相关引用:** 在Yaf手册中,关于控制器的说明:控制器的初始化方法为`init`,在控制器实例化后立即被调用[^1]。</think>### Yaf框架控制器初始化问题分析与解决方案 #### 问题原因分析 在Yaf框架中,控制器初始化方法调用遵循特定规则,您遇到的基`init`方法执行而子`_init`方法未执行的问题,主要由以下原因导致: 1. **方法命名冲突** Yaf框架对控制器初始化方法有严格约定: - 框架**自动调用**的初始化方法必须是`init`(小写) - 您自定义的`_init`(带下划线)方法**不会被框架自动调用**[^1] ```mermaid graph LR A[请求到达] --> B[实例化UserController] B --> C{是否存在 init 方法?} C -->|是| D[执行基init方法] C -->|否| E[跳过初始化] D --> F[基init调用$this->_init] F --> G{子是否实现 _init?} G -->|是| H[执行子_init] G -->|否| I[报错] ``` 2. **调用链中断** 如果子覆盖了`init`方法但未调用`parent::init()`,会导致基初始化链断裂: ```php class UserController extends Kepler_Controller_Base { // 错误示例:覆盖init但未调用方法 public function init() { // 此处缺少 parent::init(); } } ``` 3. **可见性错误** 抽象方法`_init`在基中的声明必须与子实现**严格匹配**: -声明为`protected abstract function _init();` -实现必须是`protected function _init()`(不能是private) #### 解决方案 ##### 方案1:规范命名(推荐) 修改基方法命名,符合Yaf规范: ```php // 基 Kepler_Controller_Base.php abstract class Kepler_Controller_Base extends Yaf_Controller_Abstract { // 使用标准init方法(无下划线) public function init() { $this->doInit(); // 调用实际初始化逻辑 } // 定义需要子实现的抽象方法 abstract protected function doInit(); } // 子 UserController.php class UserController extends Kepler_Controller_Base { // 实现初始化逻辑 protected function doInit() { // 子初始化代码 echo "UserController初始化成功!"; } } ``` ##### 方案2:显式调用方法 如果必须保留`_init`命名: ```php class UserController extends Kepler_Controller_Base { // 必须显式调用init public function init() { parent::init(); // 关键调用 // 其他初始化代码... } protected function _init() { // 子初始化代码 } } ``` #### 验证步骤 1. **检查方法可见性** 确保所有`_init`方法均为`protected`: ```php // 基 abstract protected function _init(); // 子 protected function _init() {...} ``` 2. **启用框架调试模式** 在`application.ini`中添加: ```ini ; 开启错误显示 application.dispatcher.throwException = 1 application.dispatcher.catchException = 0 ; 开启调试模式 yaf.environ = "develop" ``` 3. **添加日志追踪** 在基中添加调用日志: ```php public function init() { error_log("调用init: ".get_class($this)); $this->_init(); } ``` #### 底层原理说明 Yaf框架通过扩展层直接调用控制器的`init`方法[^2]: ```c // yaf_dispatcher.c (简化) zend_class_entry* controller = ... // 获取控制器 zend_function* init = zend_hash_str_find_ptr(&controller->function_table, "init", 4); if(init) { zend_call_method(..., init, ...); // 直接调用init方法 } ``` 这意味着: 1. 只有命名为`init`的方法会被自动调用 2. 自定义方法(如`_init`)需通过`init`显式调用 3. 方法查找区分大小写(必须全小写`init`) 通过规范命名调用链,即可解决子初始化方法未执行的问题[^3]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值