When to use self over $this?
在php 5中,使用
什么时候合适?
短的答案
Use
$this to refer to the current
object. Useself to refer to the
current class. In other words, use
$this->member for non-static members,
useself::$member for static members.
完整的答案
这里是一个例子的正确使用和
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php class X { private $non_static_member = 1; private static $static_member = 2; function __construct() { echo $this->non_static_member . ' ' . self::$static_member; } } new X(); ?> |
这里是一个例子,不使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php class X { private $non_static_member = 1; private static $static_member = 2; function __construct() { echo self::$non_static_member . ' ' . $this->static_member; } } new X(); ?> |
这里是一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php class X { function foo() { echo 'X::foo()'; } function bar() { $this->foo(); } } class Y extends X { function foo() { echo 'Y::foo()'; } } $x = new Y(); $x->bar(); ?> |
这里是一个例子所使用的多态性行为及
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php class X { function foo() { echo 'X::foo()'; } function bar() { self::foo(); } } class Y extends X { function foo() { echo 'Y::foo()'; } } $x = new Y(); $x->bar(); ?> |
The idea is that
$this->foo() calls thefoo() member function of whatever is the exact type of the current object. If the object is oftype X , it thus callsX::foo() . If the object is oftype Y , it callsY::foo() . But with self::foo(),X::foo() is always called.
从http:/ / / / www.phpbuilder.com板允许吗?10354489:T =
通过http:/ / / member.php board.phpbuilder.com?145249 -激光
关键字self不仅仅引用"当前类",至少不会以限制静态成员的方式引用。在非静态成员的上下文中,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Person { private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } public function getTitle() { return $this->getName()." the person"; } public function sayHello() { echo"Hello, I'm".$this->getTitle()."<br/>"; } public function sayGoodbye() { echo"Goodbye from".self::getTitle()."<br/>"; } } class Geek extends Person { public function __construct($name) { parent::__construct($name); } public function getTitle() { return $this->getName()." the geek"; } } $geekObj = new Geek("Ludwig"); $geekObj->sayHello(); $geekObj->sayGoodbye(); |
这将输出:
Hello, I'm Ludwig the geek
Goodbye from Ludwig the person
不使用
自我还有另一个方面:值得一提。恼人的是,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Person { public static function status() { self::getStatus(); } protected static function getStatus() { echo"Person is alive"; } } |
如果我们称之为
1 2 3 4 5 6 7 8 9 | class Deceased extends Person { protected static function getStatus() { echo"Person is deceased"; } } |
调用
php 5.3有一个解决方案。
参见PHP文档
所以回答这个问题,而不是按要求…
为了真正理解我们在讨论
让我们从讨论什么是类和对象开始。好的。概念上的类和对象
那么,什么是班级?很多人把它定义为对象的蓝图或模板。实际上,您可以在这里了解更多关于PHP类的信息。在某种程度上,这才是真正的。让我们看一个类:好的。
1 2 3 4 5 6 | class Person { public $name = 'my name'; public function sayHello() { echo"Hello"; } } |
如您所知,该类上有一个名为
需要注意的是,类是一个静态结构。这意味着类
另一方面,对象被称为类的实例。这意味着我们获取类的"蓝图",并使用它来创建动态副本。这个副本现在专门绑定到它存储的变量。因此,对实例的任何更改都是该实例的本地更改。好的。
1 2 3 4 | $bob = new Person; $adam = new Person; $bob->name = 'Bob'; echo $adam->name; //"my name" |
我们使用
因此,我们说类是全局结构,对象是局部结构。不要担心有趣的
另一件我们应该讨论的事情是,我们可以检查一个实例是否是一个
所以让我们来深入研究一下类实际包含的内容。一个类包含5种类型的"东西":好的。
属性-将这些视为每个实例将包含的变量。好的。
1 2 3 | class Foo { public $bar = 1; } |
静态属性-将这些属性视为在类级别共享的变量。这意味着它们不会被每个实例复制。好的。
1 2 3 | class Foo { public static $bar = 1; } |
方法-这些是每个实例将包含的函数(并对实例进行操作)。好的。
1 2 3 | class Foo { public function bar() {} } |
静态方法-这些是在整个类中共享的函数。它们不在实例上操作,而是只在静态属性上操作。好的。
1 2 3 | class Foo { public static function bar() {} } |
常量-类解析的常量。这里不再深入,但为了完整性增加了:好的。
1 2 3 | class Foo { const BAR = 1; } |
因此,基本上,我们使用关于静态的"提示"来存储类和对象容器上的信息,这些提示标识信息是否共享(因此是静态的)或者不共享(因此是动态的)。好的。状态和方法
在方法内部,对象的实例由
如果静态调用方法,则不定义
有趣的是静态调用是如何进行的。那么让我们来谈谈我们如何访问这个州:好的。访问状态
所以现在我们已经存储了这个状态,我们需要访问它。这可能会变得有点棘手(或者说有点复杂),所以让我们将其分为两种观点:从实例/类外部(比如从普通函数调用或全局范围)和实例/类内部(从对象上的方法内部)。好的。从实例/类外部
从实例/类的外部来看,我们的规则非常简单和可预测。我们有两个操作符,如果我们处理的是实例或类静态的,每个操作符都会立即告诉我们:好的。
-> -对象操作符-当我们访问一个实例时,总是使用它。好的。1
2$bob = new Person;
echo $bob->name;需要注意的是,调用
Person->foo 是没有意义的(因为Person 是一个类,而不是一个实例)。因此,这是一个分析错误。好的。:: —作用域解析操作符—它总是用于访问类静态属性或方法。好的。1echo Foo::bar()此外,我们可以用同样的方法对对象调用静态方法:好的。
1echo $foo::bar()需要特别注意的是,当我们从外部执行此操作时,对象的实例隐藏在
bar() 方法中。这意味着它与跑步完全相同:好的。1
2
因此,静态调用中没有定义
这里的情况有点变化。使用相同的运算符,但它们的含义变得明显模糊。好的。
对象运算符
1 2 3 4 5 6 | class Foo { public $a = 1; public function bar() { return $this->a; } } |
使用对象操作符:
所以这就是我们所期望的。好的。
在静态上下文中好的。
在静态上下文中,使用
:: 进行的任何调用也将是静态的。让我们来看一个例子:好的。1
2
3
4
5
6
7
8class Foo {
public function bar() {
return Foo::baz();
}
public function baz() {
return isset($this);
}
}调用
Foo::bar() 将静态调用baz() 方法,因此不会填充$this 。值得注意的是,在最新版本的php(5.3+)中,这将触发E_STRICT 错误,因为我们静态地调用非静态方法。好的。在实例上下文中好的。
另一方面,在实例上下文中,使用
:: 进行的调用依赖于调用的接收者(我们调用的方法)。如果方法被定义为static ,那么它将使用静态调用。如果不是,它将转发实例信息。好的。因此,看看上面的代码,调用
$foo->bar() 将返回true ,因为"静态"调用发生在实例上下文中。好的。
有道理?我不这么认为。这让人困惑。好的。快捷关键词
因为使用类名将所有东西捆绑在一起是相当脏的,所以PHP提供了3个基本的"快捷键"关键字以使范围解析更容易。好的。
self —指当前的类名。因此,self::baz() 与Foo 类内的Foo::baz() 相同(任何方法)。好的。parent —指当前类的父类。好的。static —这是指被调用的类。由于继承,子类可以重写方法和静态属性。因此,使用static 而不是类名来调用它们可以让我们解析调用的来源,而不是当前级别。好的。
实例
要理解这一点,最简单的方法是从一些例子开始。让我们选一个班级:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class Person { public static $number = 0; public $id = 0; public function __construct() { self::$number++; $this->id = self::$number; } public $name =""; public function getName() { return $this->name; } public function getId() { return $this->id; } } class Child extends Person { public $age = 0; public function __construct($age) { $this->age = $age; parent::__construct(); } public function getName() { return 'child: ' . parent::getName(); } } |
现在,我们也在研究遗产。暂时忽略这是一个坏的对象模型,但让我们看看当我们使用它时会发生什么:好的。
1 2 3 4 5 6 7 8 9 |
所以ID计数器在两个实例和子实例之间共享(因为我们使用
1 2 3 |
注意,我们每次都在执行
注意,调用上下文决定是否使用实例。因此:好的。
1 2 3 4 5 | class Foo { public function isFoo() { return $this instanceof Foo; } } |
并不总是正确的。好的。
1 2 3 4 5 6 7 | class Bar { public function doSomething() { return Foo::isFoo(); } } $b = new Bar; var_dump($b->doSomething()); // bool(false) |
现在这里真的很奇怪。我们调用的是另一个类,但是传递给
这会导致各种各样的错误和概念性的错误。因此,我强烈建议避免
注意,静态方法和属性由每个人共享。这使得它们基本上是全局变量。所有的问题都是全球性的。因此,如果您不愿意将信息存储在真正的全局性中,那么我真的会犹豫是否将其存储在静态方法/属性中。好的。注意事项3
一般来说,您需要使用
太糟糕了,回去读吧。可能太长了,但是太长了,因为这是一个复杂的主题好的。TL/DRα2
好的,很好。简而言之,
如果使用了对象操作符(
不幸的是,自
因为
因为
1 2 | Example: $derek = new Person(); |
$derek现在是个人的一个具体实例。每个人都有名字和姓氏,但是$derek有一个特定的名字和姓氏(derek martin)。在$derek实例中,我们可以将其称为$this->first_name和$this->last_name。
classname::用于引用该类型的类及其静态变量、静态方法。如果它有帮助,你可以用"共享"在精神上替换"静态"这个词。因为它们是共享的,所以它们不能引用$this,后者指的是特定的实例(不是共享的)。静态变量(即静态$db_连接)可以在对象类型的所有实例之间共享。例如,所有数据库对象共享一个连接(静态$connection)。
静态变量示例:假设我们有一个包含单个成员变量的数据库类:静态$num_连接;现在,把它放到构造函数中:
1 2 3 4 5 6 7 8 9 10 11 | function __construct() { if(!isset $num_connections || $num_connections==null) { $num_connections=0; } else { $num_connections++; } } |
正如对象有构造函数一样,它们也有析构函数,在对象死亡或未设置时执行析构函数:
1 2 3 4 | function __destruct() { $num_connections--; } |
每次我们创建一个新实例时,它都会将我们的连接计数器增加一个。每次销毁或停止使用实例时,它都会将连接计数器减少一个。通过这种方式,我们可以监视与我们一起使用的数据库对象的实例数:
1 | echo DB::num_connections; |
因为$num_连接是静态的(共享的),所以它将反映活动数据库对象的总数。您可能已经看到了用于在数据库类的所有实例之间共享数据库连接的这种技术。这样做是因为创建数据库连接需要很长时间,所以最好只创建一个并共享它(这称为单例模式)。
静态方法(即public static view::format_phone_number($digits))可以在不首先实例化其中一个对象的情况下使用(即,它们在内部并不引用$this)。
静态方法示例:
1 2 3 4 5 6 |
如您所见,public静态函数prettyname对对象一无所知。它只是处理你传入的参数,就像一个普通函数,它不是对象的一部分。那么,如果我们不把它作为物体的一部分,为什么还要麻烦呢?
自我:如果要在具有要引用的静态方法的对象外部进行编码,则必须使用该对象的名称视图::格式"电话号码($phoneu number)"调用它;如果要在具有要引用的静态方法的对象内进行编码,则可以使用对象的名称视图::格式化电话号码($pn),也可以使用self::格式化电话号码($pn)快捷方式
静态变量也是如此:示例:View::Templates_Path与Self::Templates_Path
在db类中,如果我们引用其他对象的静态方法,我们将使用该对象的名称:示例:session::getUserSonline();
但是如果db类想要引用它自己的静态变量,它只会说self:示例:self::connection;
希望这有助于解决问题。)
从这篇博文:
self refers to the current classself can be used to call static functions and reference static member variablesself can be used inside static functionsself can also turn off polymorphic behavior by bypassing the vtable$this refers to the current object$this can be used to call static functions$this should not be used to call static member variables. Useself instead.$this can not be used inside static functions
在PHP中,使用self关键字访问静态属性和方法。
问题是,您可以在任何地方用
考虑此代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class ParentClass { function test() { self::who(); // will output 'parent' $this->who(); // will output 'child' } function who() { echo 'parent'; } } class ChildClass extends ParentClass { function who() { echo 'child'; } } $obj = new ChildClass(); $obj->test(); |
在本例中,
现在我们可以看到self指的是它被调用的类,而
因此,只有当
在类定义中,$this引用当前对象,self引用当前类。
有必要使用self引用类元素,并使用$this引用对象元素。
1 2 3 |
根据http://www.php.net /手动/恩/ language.oop5.static.php没有
Here is an example of correct usage of $this and self for non-static
and static member variables:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php class X { private $non_static_member = 1; private static $static_member = 2; function __construct() { echo $this->non_static_member . ' ' . self::$static_member; } } new X(); ?> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class ParentClass { function test() { self::which(); // output 'parent' $this->which(); // output 'child' } function which() { echo 'parent'; } } class ChildClass extends ParentClass { function which() { echo 'child'; } } $obj = new ChildClass(); $obj->test(); |
输出:起源小孩
因为这里没有人谈论性能,这里有一个小基准我做了(5.6):
1 2 3 4 5 | Name | Time | Percent ----------|---------|--------- $this-> | 0.99163 | 106.23% self:: | 0.96912 | 103.82% static:: | 0.93348 | 100% |
这些是2000 000次运行的结果,下面是我使用的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?php require '../vendor/autoload.php'; // My small class to do benchmarks // All it does is looping over every test x times and record the // time it takes using `microtime(true)` // Then, the percentage is calculated, with 100% being the quickest // Times are being rouned for outputting only, not to calculate the percentages $b = new Tleb\Benchmark\Benchmark(2000000); class Foo { public function calling_this() { $this->called(); } public function calling_self() { self::called(); } public function calling_static() { static::called(); } public static function called() { } } $b->add('$this->', function () { $foo = new Foo; $foo->calling_this(); }); $b->add('self::', function () { $foo = new Foo; $foo->calling_self(); }); $b->add('static::', function () { $foo = new Foo; $foo->calling_static(); }); $b->run(); |
我认为问题不在于是否可以通过调用
例如,无论您使用的是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Person{ private $name; private $address; public function __construct($new_name,$new_address){ $this->name = $new_name; $this->address = $new_address; } } class Person{ private $name; private $address; public function __construct($new_name,$new_address){ self::$name = $new_name; self::$address = $new_address; } } |
当
- 对象指针$this指向当前对象。
- 类值"static"是指当前对象。
- 类值"self"是指它在中定义的确切类。
- 类值"parent"是指它在中定义的确切类的父级。
请参见下面显示重载的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php class A { public static function newStaticClass() { return new static; } public static function newSelfClass() { return new self; } public function newThisClass() { return new $this; } } class B extends A { public function newParentClass() { return new parent; } } $b = new B; var_dump($b::newStaticClass()); // B var_dump($b::newSelfClass()); // A because self belongs to"A" var_dump($b->newThisClass()); // B var_dump($b->newParentClass()); // A class C extends B { public static function newSelfClass() { return new self; } } $c = new C; var_dump($c::newStaticClass()); // C var_dump($c::newSelfClass()); // C because self now points to"C" class var_dump($c->newThisClass()); // C var_dump($b->newParentClass()); // A because parent was defined *way back* in class"B" |
大多数时候,您希望引用当前类,这就是为什么使用
换句话说,使用
在子/父场景中,
另外,由于
仅供参考,从php 5.3开始,当处理实例化对象以获取当前作用域值时,与使用
http://ideone.com/7ethy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Foo { const NAME = 'Foo'; //Always Foo::NAME (Foo) due to self protected static $staticName = self::NAME; public function __construct() { echo $this::NAME; } public function getStaticName() { echo $this::$staticName; } } class Bar extends Foo { const NAME = 'FooBar'; /** * override getStaticName to output Bar::NAME */ public function getStaticName() { $this::$staticName = $this::NAME; parent::getStaticName(); } } $foo = new Foo; //outputs Foo $bar = new Bar; //outputs FooBar $foo->getStaticName(); //outputs Foo $bar->getStaticName(); //outputs FooBar $foo->getStaticName(); //outputs FooBar |
使用上面的代码并不是常见的或推荐的实践,而是简单地说明它的用法,并且更像是"你知道吗?"关于原始海报的问题。
它还代表了
我遇到了同样的问题,简单的答案是:
- $这需要类的一个实例
- 自我:不
每当您使用静态方法或静态属性,并且希望在没有实例化类的对象的情况下调用它们时,您需要使用self::来调用它们,因为$这总是要求创建对象。
如果您想调用一个类的方法而不创建该类的对象/实例,那么可以使用
例1:使用
1 2 3 4 | class classA { const FIXED_NUMBER = 4; self::POUNDS_TO_KILOGRAMS } |
如果要在类外部调用它,请使用
案例2:静态特性
1 2 3 4 5 | class classC { public function __construct() { self::$_counter++; $this->num = self::$_counter; } } |
根据php.net,这里有三个特殊的关键字:
另一方面,