Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/248.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
理解范围解析运算符';PHP语言中的s定义_Php_Inheritance_Static_Static Methods_Scope Resolution Operator - Fatal编程技术网

理解范围解析运算符';PHP语言中的s定义

理解范围解析运算符';PHP语言中的s定义,php,inheritance,static,static-methods,scope-resolution-operator,Php,Inheritance,Static,Static Methods,Scope Resolution Operator,在php手册中,它们定义了范围解析运算符,如下所示: 范围解析运算符(也称为Paamayim-Nekudotayim)或更简单的术语,即双冒号,是允许访问静态、常量和重写属性或类的方法的标记 我的理解是,因为我们不能用$this评估静态属性、类常量和静态方法,所以我们需要:。我不明白为什么允许:从类内部评估非静态函数。可以说,子类可能希望使用parent::baseClassMethod()评估父类中定义的方法,但是它可能也想评估父类中定义的属性,但是:无法评估属性。可以说父类的属性是继承的,所

在php手册中,它们定义了范围解析运算符,如下所示:

范围解析运算符(也称为Paamayim-Nekudotayim)或更简单的术语,即双冒号,是允许访问静态、常量和重写属性或类的方法的标记

我的理解是,因为我们不能用
$this
评估静态属性、类常量和静态方法,所以我们需要
。我不明白为什么允许
从类内部评估非静态函数。可以说,子类可能希望使用
parent::baseClassMethod()
评估父类中定义的方法,但是它可能也想评估父类中定义的属性,但是
无法评估属性。可以说父类的属性是继承的,所以我们可以简单地用
$this->prop
来评估它们,但方法也是如此。只有当方法在子类中被重写时,我们才对它们使用
::
。类似地,我们需要
来评估子类中重写的属性。与php手动定义相反,如果尝试使用
::
评估重写的属性,则会抛出错误

为了说明我的观点,我有以下PHP代码示例:

error_reporting(E_ALL);
class myClass {
    private $prop = 786; 
    public $prop2 = 123;

    public function changeType($var, $type){
        settype($var, $type);
        echo "function assessed through self";
    }
    public function display_prop(){
        self::changeType(1, "string"); //why does this not throw error for non static function?
        var_dump(self::$prop); //throws error; can't assess properties with self as expected.
    }    
}

class childCLass extends myClass {
    public $prop2 = "new"; //overriden property.

    public function display_prop(){ //overriden method.
        echo "I do different things from the base class". "</br>";      
    }
    public function dsiplay_overriden(){
        echo parent::$prop2; //Why can't assess overriden properties, as suggested in the definition?
    }
}

$obj = new myClass;
$obj->display_prop(); 

$obj2 = new childCLass;
$obj2->display_prop();
$obj2->dsiplay_overriden();

childClass::display_prop(); //This throws error as expected because non-static method.
错误报告(E_ALL);
类myClass{
私人$prop=786;
公共支出$prop2=123;
公共函数changeType($var,$type){
settype($var$type);
echo“通过自我评估功能”;
}
公共功能显示_prop(){
self::changeType(1,“string”);//为什么这不会引发非静态函数的错误?
var_dump(self::$prop);//抛出错误;无法按预期使用self评估属性。
}    
}
类childCLass扩展了myClass{
public$prop2=“new”//重写的属性。
公共函数display_prop(){//重写的方法。
echo“我做的事情与基类不同”。
; } 公共函数dsiplay_重写(){ echo parent::$prop2;//为什么不能按照定义中的建议评估重写的属性? } } $obj=新的myClass; $obj->display_prop(); $obj2=新的子类; $obj2->display_prop(); $obj2->dsiplay_overrided(); childClass::display_prop()//这会引发预期的错误,因为该方法是非静态的。
总而言之,我主要有两个具体问题:

  • 为什么我们不能使用定义中定义的
    访问覆盖的属性
  • 与定义相反,为什么我们可以使用
    访问类中的非静态函数

  • 注:关于stackoverflow,有人问过A。没有令人满意的答案存在,而且我正在寻找一个概念性的和有见地的答案,这在programmers.stackexchange更合适

    我试试看:)

    方法和静态属性在内存中只存在一次,类实例(对象)的非静态属性在每个实例中都存在,例如,在内存中有自己的空间

  • 不能“重写”类的公共或受保护属性。相反,派生类中相同属性名的声明将“掩盖”基类声明。实际上,它们在内存中共享相同的位置,使它们“相同”,就像在全局命名空间中两次声明相同名称的变量一样。原因是继承,您继承基类的所有公共和受保护属性。 如果不继承私有属性,则派生类的实例将有两个单独的内存区域用于相同名称的属性。见下面的例子A

  • 范围解析不禁止非静态访问。PHP文档中的第一句话甚至是这样说的:
    范围解析运算符(也称为Paamayim-Nekudotayim)或更简单的术语,即双冒号,是允许访问类的静态、常量和重写属性或方法的标记。
    事实上,它解析作用域,例如,它确定是否必须访问静态(共享)或本地内存

  • 特殊变量
    $this
    只能访问本地内存,它代表“对当前实例的引用”,在非静态类方法中自动可用,但在静态方法中不可用!历史上,它来自C++(关键字“这个”),其中类方法在所有类方法的函数指针映射中组织,即所谓的V表。所有非静态类方法都会收到一个名为“this”的附加(不可见)最后一个参数,对非静态方法的调用会在运行时解析(与编译时解析的静态方法相反)

    现在,当您创建一个类的实例时,比如
    $obj=newfoo()将发生两件事-为对象分配内存,并调用类的构造函数。构造函数不能声明为静态的,因为它们负责正确初始化内存。作为非静态方法,他们将自动接收
    $this

    因此,当调用非静态方法时,如
    $obj->method()
    ,运行时环境将识别,
    $obj
    是类实例。它检查类的v-table以找到方法(它只是一个常规函数,但带有额外的参数$this),并调用它,将
    $obj
    作为
    $this
    传递,伪代码
    $vtable['Foo']['method']($obj)
    。在类方法中,您可以访问$this

    最后,静态调用非静态方法,分别以非静态方式调用静态方法: 事实上,如果你牢记这一点,你可以两者兼得

    非静态方法,使用
    Foo::bar()调用
    $此
    将为

    静态方法,使用调用<
    class A {
        public $x = 'a_x';
        protected $y = 'a_y';
        private $z = 'a_z';
    }
    class B extends A {
        public $x = 'b_x';
        protected $y = 'b_y';
        private $z = 'b_z';
    
        public static function foo() {
            echo 'foo' . PHP_EOL;
        }
        public function bar() {
            echo 'bar' . PHP_EOL;
        }
    }
    $a = new A();
    $b = new B();
    
    var_dump($a, $b);
    $b->foo();
    B::bar();
    
    object(A)#1 (3) {
      ["x"]=>
      string(3) "a_x"
      ["y":protected]=>
      string(3) "a_y"
      ["z":"A":private]=>
      string(3) "a_z"
    }
    object(B)#2 (4) {
      ["x"]=>
      string(3) "b_x"
      ["y":protected]=>
      string(3) "b_y"
      ["z":"B":private]=>
      string(3) "b_z"
      ["z":"A":private]=>
      string(3) "a_z"
    }
    foo
    bar