PHP $this变量一些理解

手册上的一个有意思的小示例。
http://www.php.net/manual/zh/language.variables.basics.php

 代码如下 复制代码

 $this = 'text'; // error
 $name = 'this';
 $$name = 'text'; // sets $this to 'text'

 echo $$name;

在PHP的词法分析时,$this变量是符合其规则的,在语法解析生成中间代码时,PHP内核会根据变量类型在生成赋值的中间代码时判断是否为$this变量,如果是则报错。这里为什么要报错呢?因为this作为一个特殊的变量,在对象的成员方法等调用初始化时会将this变量添加到活动符号表。

在类的成员方法里面,可以用 ->(对象运算符):$this->property(其中 property 是该属性名)这种方式来访问非静态属性。

当一个方法在类定义内部被调用时,有一个可用的伪变量 $this。$this 是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象静态调用时也可能是另一个对象)。

在词法分析、语法分析并生成中间代码时,$this作为一个特殊的变量存在,特别是在生成中间代码时,代码中充斥着对于this的特殊处理。这些都是为后面的运行做准备,如识别标记出某处使用this变量,在存储opcode的zend_op_array结构体中专门有一个变量this_var标识是否有this变量。一个函数或一个类方法都会生成一个新的zend_op_array,在生成中间代码时,判断当前变量是否为this变量。

this变量在执行过程中会有两种存在状态,一种是全局传递的状态,存储在EG(This),一种是当前作用域状态,以this变量存储在EG(active_symbol_table)(当前执行环境的活动符号表)。
在我们执行一个 op_array 时,比如一个对象的方法,PHP内核会给这个 op_array 生成一个 zendexecutedata ,在生成初始化时,EG(This) 会添加到EG(active_symbol_table) 。
在方法调用过程中,如果有用到this变量,则会直接取EG(active_symbol_table)的值。

那么一个对象中的EG(This)在哪里初始化呢?
就EG(This)变量本身来说,在我们初始化PHP的执行环境时,它和其它全局变量(如EG(scope)等)一样都会被初始化为NULL。
对于一个对象来说,当我们创建了一个对象,调用时,PHP内核会将当前获得的对象直接赋值给EG(This),而这个当前获得的对象是在通过new操作生成对象时创建的对象本身。

如下这个简单示例:

 代码如下 复制代码
 class Foo {
      public $var = 10;
 
      function t() {
           echo $this->var;    
      }
 
      function t2() {
       echo 33;
  }
 }
 
 $foo = new Foo();
 $foo->t();

其主程序流程生成的中间代码如下:

 代码如下 复制代码
        function name:  (null)
 number of ops:  8
 compiled vars:  !0 = $foo
 line     # *  op                           fetch          ext  return  operands
 ---------------------------------------------------------------------------------
    2     0  >   NOP                                                     
   15     1      ZEND_FETCH_CLASS                              4  :1      'Foo'
          2      NEW                                              $2      :1
          3      DO_FCALL_BY_NAME                              0         
          4      ASSIGN                                                   !0, $2
   16     5      ZEND_INIT_METHOD_CALL                                    !0, 't'
          6      DO_FCALL_BY_NAME                              0         
          7    > RETURN   
                                               1this

变量原始的对象值出生在 opcode NEW,经过了赋值(ASSIGN)后,在方法初始化时,将变量本身传递给执行环境的调用者,调用者又在执行调用(DO_FCALL_BY_NAME)时将变量传递给EG(This),当执行这个方法的op_array时,初始化当前作用域的环境(zend_execute_data)时,会将EG(This)作为$this变量添加到活动符号表,后续方法中的$this变量的使用就会直接取符号表的变量。

时间: 2024-08-30 20:36:40

PHP $this变量一些理解的相关文章

《Java程序员面试秘笈》—— 面试题9 对于类的静态变量的理解

面试题9 对于类的静态变量的理解 运行下面程序,请选择输出结果. public class x { private static int a; public static void main(String[] args) { modify(a); System.out.println(a); } public static void modify(int a) { a++; }} (a)0 (b)1 (c)2 (d)3 考点:考察求职者对于类的静态变量的理解. 出现频率: [面试题解析]类的静态

关于javascript中变量作用域理解

现在就结合网上的一篇文章在重新回顾下作用域这个东西吧. 作用域和上下文并不是同一个东西,很多人可能会把它搞混.每一个函数调用都联系着一个作用域和一个上下文.根本上来说,作用域是基于函数的而上下文是基于对象的.换句话说,作用域与函数调用是能够获取的变量有联系,它对与每一次调用来说都是独一无二的.上下文常常代表this变量的值,它指向"拥有"当前执行的这段代码的对象. 变量作用域 一个变量的作用域是程序源代码中定义这个变量的区域.全局变量拥有全局作用域,在js代码里的任何地方都是有定义的.

【Solidity】4.单位和全局可变量 - 深入理解Solidity

索引 [Solidity]1.一个Solidity源文件的布局 [Solidity]2.合约的结构体 [Solidity]3.类型 [Solidity]4.单位和全局可变量 [Solidity]5.表达式和控制结构 [Solidity]6. 合约 [Solidity]7. 部件 [Solidity]8. 杂项 单位和全局可变量 Ether单元 一个字面上的数字可以带有wei,finney,szabo或者以太网的后缀,可以在以太网的子目录之间进行转换,其中没有后缀的以太网货币号被假定为魏. 2 e

Java中的环境变量设置---理解

java中环境变量的设置,主要是设置设置JAVA_HOME,CLASSPATH,在path变量中增加java的bin目录.当然现在都是用工具开发,可以不设置CLASSPATH,可能会有问题,所以还是尽量设置. JAVA_HOME C:Javajdk1.6.0_30(java的安装目录,) PATH C:Javajdk1.6.0_30bin(%JAVA_HOME%lib)(不要新建path在原来的path路径上新加java到bin的路径就可以了,) CLASSPATH .;%JAVA_HOME%l

MySQL运维实战(一)之 系统变量潜规则

Agenda 踩坑经历 测试用例 结论 实战用途 一.踩坑经历 设置了slow log 的时间,但是抓不到正确的sql 设置了read_only ,为啥还有写入进来 设置了sql_safe_update , 为啥还能全表删除 测试方法的不对,导致设置了read_only后,有的时候可以insert,有的时候不可以insert 太多这样的问题, 所以打算一窥究竟 二.测试用例 测试设置参数后,是否会生效 2.1 官方文档说明 https://dev.mysql.com/doc/refman/5.7

《视图更新与关系数据库理论》——2.4 关系变量谓词

2.4 关系变量谓词 在第1章中,当我介绍抛砖引玉的例子(供应商与零部件数据库)时,曾提到了这样一件事: 表S的内容列出了签过合同的供应商.每个供应商有一个唯一的供应商编号SNO.可能不唯一的供应商名字SNAME(尽管图1.1中的样本值恰好是唯一的),以及状态值STATUS和位置CITY. 当然,在第1章中的"表S"似乎应该叫作"关系变量S"更加准确,不过这并不是重点.重点在于:第一,目前的文字代表了关系变量S的意义,并且更容易被用户理解:第二,这种意义的措辞实际上

多层级理解闭包

闭包 闭包的概念困惑了我很久,记得当时我面试的时候最后一面有一个问题就是问题关于闭包的问题,然而到现在已经完全不记得当时的题目是啥了,但仍然能够回忆起当时不会的feel,虽然面试官非常友好的提醒了我应该用闭包,可是在我吭哧半天出不来的情况下,迷面试官还是耐心的给我讲了什么是闭包:有一个函数处理之后返回另一个函数,且只能执行一次.然后给我把当时的题写了一下,直到我出来都没有理解什么是闭包,那个题到底是什么题,要不是其他都答出来的话,估计都要挂.哎~一个菜鸟的心路历程.于是,闭包就成了我心里的梗.

C++编程中队内联函数的理解和使用_C 语言

函数调用过程c++经过编译生成可执行程序文件exe,存放在外存储器中.程序启动,系统从外存储器中将可执行文件装载到内存中,从入口地址(main函数起始处)开始执行.程序执行中遇到了对其他函数的调用,就暂停当前函数的执行,并保存下一条指令的地址作为从被调函数返回后继续执行的入口点,保存现场.然后转到被调函数的入口地址执行被调函数.遇到return语句或者被调函数结束后,恢复先前保存的现场,从先前保存的返回地址处继续执行主调函数的其余部分. 内联函数函数调用需要进行现场保护,以便在函数调用之后继续进

详解C++编程中类的成员变量和成员函数的相关知识_C 语言

C++类的成员变量和成员函数 类是一种数据类型,它类似于普通的数据类型,但是又有别于普通的数据类型.类这种数据类型是一个包含成员变量和成员函数的一个集合. 类的成员变量和普通变量一样,也有数据类型和名称,占用固定长度的内存空间.但是,在定义类的时候不能对成员变量赋值,因为类只是一种数据类型,本身不占用内存空间,而变量的值则需要内存来存储. 类的成员函数也和普通函数一样,都有返回值和参数列表,它与一般函数的区别是:成员函数是一个类的成员,出现在类体中,它的作用范围由类来决定:而普通函数是独立的,作