什么时候使用自己超过$这个?
在PHP 5中,使用self
和$this
什么区别?
什么时候适合?
简答
使用
$this
来引用当前对象。 使用self
来引用当前的类。 换句话说,对非静态成员使用$this->member
,对静态成员使用self::$member
。
完整答案
下面是非静态和静态成员variables正确使用$this
和self
的示例:
<?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(); ?>
这里是$this
和self
用于非静态和静态成员variables的一个例子:
<?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(); ?>
这里是$this
对于成员函数的多态性的一个例子:
<?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(); ?>
这是一个通过使用self
来抑制成员函数的多态行为的例子:
<?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(); ?>
这个想法是,
$this->foo()
调用任何>是当前对象的确切types的foo()
成员函数。 如果对象是type X
,那么它调用X::foo()
。 如果对象是type Y
,则调用Y::foo()
。 但是用> self :: foo(),总是调用X::foo()
。
从http://www.phpbuilder.com/board/showthread.php?t=10354489 :
关键字self并不仅仅指“当前类”,至less不会限制你成为静态成员。 在非静态成员的上下文中, self
还为当前对象提供了绕过vtable的方法( 请参阅vtable上的wiki )。 就像你可以使用parent::methodName()
来调用函数的父级版本一样,所以你可以调用self::methodName()
来调用方法的当前类实现。
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();
这将输出:
你好,我是路德维格的极客
再见了路德维希这个人
sayHello()
使用$this
指针,所以调用vtable来调用Geek::getTitle()
。 sayGoodbye()
使用self::getTitle()
,所以不使用vtable,并调用Person::getTitle()
。 在这两种情况下,我们正在处理实例化对象的方法,并可以访问被调用函数中的$this
指针。
不要使用self::
,使用static::
自我的另一个方面是值得一提的。 令人讨厌的self::
是指定义点的范围不在执行点 。 考虑这个简单的类有两种方法:
class Person { public static function status() { self::getStatus(); } protected static function getStatus() { echo "Person is alive"; } }
如果我们调用Person::status()
我们将看到“Person is alive”。 现在考虑一下当我们创build一个inheritance自这个类的类时会发生什么:
class Deceased extends Person { protected static function getStatus() { echo "Person is deceased"; } }
调用Deceased::status()
我们期望看到“Person is deceased”,但是当我们定义调用self::getStatus()
时,我们看到的是“Person is alive”,因为scope包含原始方法定义。
PHP 5.3有一个解决scheme。 static::
parsing运算符实现了“后期静态绑定”,这是一种奇怪的说法,它被称为类的范围。 将status()
的行更改为static::getStatus()
,结果就是您所期望的。 在旧版本的PHP中,你将不得不寻找一个kludge来做到这一点。
请参阅PHP文档
所以要回答这个问题并不是要求…
$this->
指向当前对象(类的一个实例),而static::
指向一个类
为了真正理解我们在讨论self
和$this
时所谈论的内容,我们需要在概念层面和实践层面上深入挖掘。 我真的不觉得有什么答案可以做到这一点,所以这是我的尝试。
我们先来谈谈一个类和一个对象是什么。
类和对象,概念上
那么,什么是 课堂 ? 很多人将其定义为对象的蓝图或模板 。 事实上,你可以在这里阅读更多关于PHP的类 。 在某种程度上,这就是它的真正原因。 我们来看一个类:
class Person { public $name = 'my name'; public function sayHello() { echo "Hello"; } }
正如你所看到的,这个类有一个名为$name
的属性和一个名为sayHello()
的方法(函数sayHello()
。
注意到这个类是一个静态结构是非常重要的。 这意味着,一旦定义了Person
类,在你看的每个地方总是一样的。
另一方面,对象是所谓的类的实例 。 这意味着我们把课程的“蓝图”,并用它来做一个dynamic的副本。 这个副本现在专门绑定到它所存储的variables。因此,对实例的任何更改都是本地的。
$bob = new Person; $adam = new Person; $bob->name = 'Bob'; echo $adam->name; // "my name"
我们使用new
运算符创build一个类的新实例 。
因此,我们说一个类是一个全局结构,一个对象是一个局部结构。 不要担心这个有趣的语法,我们将稍微介绍一下。
我们应该讨论的另一件事是,我们可以检查一个实例是否是一个特定类的instanceof
: $bob instanceof Person
如果$bob
实例是使用Person
类或 Person
的子类创build的,则返回一个布尔值。
定义国家
所以让我们来深入了解一个类实际包含的内容。 一类包含5类“事物”:
-
属性 – 将这些视为每个实例将包含的variables。
class Foo { public $bar = 1; }
-
静态属性 – 将这些视为在类级别共享的variables。 这意味着它们从不被每个实例复制。
class Foo { public static $bar = 1; }
-
方法 – 这些是每个实例将包含的function(并对实例进行操作)。
class Foo { public function bar() {} }
-
静态方法 – 这是在整个类中共享的函数。 它们不对实例进行操作,而是仅对静态属性进行操作。
class Foo { public static function bar() {} }
-
常量 – 类parsing的常量。 这里不做更深入的了解,但为了完整性,
class Foo { const BAR = 1; }
所以基本上,我们使用关于静态的 “提示”来存储关于类和对象容器的信息,这些提示标识信息是共享的(因此是静态的)还是不dynamic的(因此是静态的)。
状态和方法
在方法内部,一个对象的实例由$this
variables表示。 该对象的当前状态是存在的,并且改变(改变)任何属性将导致该实例的改变(但不是其他的)。
如果一个方法被静态调用, $this
variables没有被定义 。 这是因为没有实例与静态调用相关联。
这里有趣的是静态调用。 那么让我们来谈谈我们如何访问国家:
进入状态
所以现在我们已经存储了这个状态,我们需要访问它。 这可能会有点棘手(或者多一点),所以让我们把它分成两个视点:从一个实例/类的外面(比如来自一个普通的函数调用,或者来自全局作用域)和一个实例/类(从对象的方法内)。
从实例/类之外
从实例/类的外部,我们的规则是非常简单和可预测的。 我们有两个操作符,每个操作符都会立即告诉我们是否正在处理实例或类的静态:
-
->
– object-operator – 当我们访问一个实例时,总是使用它。$bob = new Person; echo $bob->name;
请注意,调用
Person->foo
是没有意义的(因为Person
是一个类,而不是实例)。 因此,这是一个parsing错误。 -
::
– scope-resolution-operator – 这总是用来访问一个类的静态属性或方法。echo Foo::bar()
另外,我们可以用相同的方法在一个对象上调用静态方法:
echo $foo::bar()
注意到当我们从外面做这件事时 ,对象的实例对
bar()
方法隐藏是非常重要的。 这意味着它和跑步完全一样:$class = get_class($foo); $class::bar();
因此, $this
在静态调用中没有定义。
从实例/类的内部
事情在这里变了一下。 使用相同的操作符,但其含义变得明显模糊。
object-operator ->
仍然用来调用对象的实例状态。
class Foo { public $a = 1; public function bar() { return $this->a; } }
使用object-operator: $foo->bar()
调用$foo
( Foo
一个实例bar()
上的bar()
方法将导致实例版本为$a
。
所以这就是我们的期望。
::
运算符的含义虽然有所改变。 它取决于调用当前函数的上下文:
-
在静态的上下文中
在静态上下文中,使用
::
任何调用也将是静态的。 我们来看一个例子:class 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个基本的“快捷键”关键字,使得作用域parsing更容易。
-
self
– 这是指当前的类名称。 所以self::baz()
与Foo
类(其中的任何方法Foo::baz()
中的Foo
Foo::baz()
相同。 -
parent
– 这是指当前类的父级。 -
static
– 这是指被调用的类。 由于inheritance,子类可以覆盖方法和静态属性。 因此,使用static
而不是类名来调用它们,可以让我们解决调用的来源,而不是当前的级别。
例子
理解这个最简单的方法是开始看一些例子。 我们来选一个class:
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(); } }
现在,我们也在这里看待inheritance。 忽略一下,这是一个不好的对象模型,但是让我们看看当我们玩这个时会发生什么:
$bob = new Person; $bob->name = "Bob"; $adam = new Person; $adam->name = "Adam"; $billy = new Child; $billy->name = "Billy"; var_dump($bob->getId()); // 1 var_dump($adam->getId()); // 2 var_dump($billy->getId()); // 3
所以ID计数器在两个实例和孩子之间共享(因为我们使用self
来访问它,如果我们使用static
,我们可以在子类中覆盖它)。
var_dump($bob->getName()); // Bob var_dump($adam->getName()); // Adam var_dump($billy->getName()); // child: Billy
请注意,我们每次都执行Person::getName()
实例方法。 但是我们使用parent::getName()
在一个案例中(子案例)。 这是什么使这种方法强大。
谨慎的字眼#1
请注意,调用上下文是决定是否使用实例的原因。 因此:
class Foo { public function isFoo() { return $this instanceof Foo; } }
并不总是如此。
class Bar { public function doSomething() { return Foo::isFoo(); } } $b = new Bar; var_dump($b->doSomething()); // bool(false)
现在这里真的很奇怪。 我们调用一个不同的类,但是传递给Foo::isFoo()
方法的$bar
是$bar
的实例。
这可能会导致各种各样的错误和概念WTF-ery。 所以我强烈build议避免在实例方法内的任何东西除了那些三个虚拟的“捷径”关键字( static
, self
和parent
)的::
运算符。
谨慎的字眼#2
请注意,每个人都共享静态方法和属性。 这使得它们基本上是全局variables。 与全局相同的问题。 所以我会真的犹豫是否将信息存储在静态的方法/属性中,除非你对它是真正的全球化感到满意。
警告词#3
一般来说,你会想通过使用static
而不是self
来使用Late-Static-Binding。 但是请注意,它们不是一回事,所以说“总是使用static
而不是self
是一种短视,相反,停下来思考一下你想要做的调用,并想想如果你希望子类能够覆盖静态解决的调用。
TL / DR
太糟糕了,回去看看吧。 这可能太长,但这是一个很复杂的话题
TL / DR#2
好的。 简而言之, self
用于引用类中的当前类名 ,其中$this
指的是当前对象实例 。 请注意, self
是一个复制/粘贴快捷方式。 你可以安全地用你的类名取代它,它会正常工作。 但$this
是一个dynamicvariables,不能提前确定(甚至可能不是你的class级)。
TL / DR#3
如果使用了对象操作符( ->
),那么你总是知道你正在处理一个实例。 如果使用范围parsing运算符( ::
,则需要有关上下文的更多信息(我们是否在对象上下文中?是否在对象之外?等等)。
self
(不是$ self)是指类的types ,其中$this
指的是类的当前实例 。 self
用于静态成员函数以允许您访问静态成员variables。 $this
用于非静态成员函数,并且是对成员函数被调用的类的实例的引用。
因为this
是一个对象,所以你使用它: $this->member
因为self
不是一个对象,所以它基本上是一个自动引用当前类的types,就像self::member
$ this->用于引用类的variables(成员variables)或方法的特定实例。
Example: $derek = new Person();
$ derek现在是Person的特定实例。 每个人都有一个名字和一个姓氏,但$ derek有一个特定的名字和姓氏(德里克·马丁)。 在$ derek实例中,我们可以将这些引用为$ this-> first_name和$ this-> last_name
ClassName ::用于引用该类的types及其静态variables,静态方法。 如果有帮助的话,你可以用“共享”的思维来replace“静态”一词。 因为它们是共享的,所以它们不能引用$ this,这是指特定的实例(不共享)。 静态variables(即静态$ db_connection)可以在一个对象types的所有实例之间共享。 例如,所有的数据库对象共享一个连接(静态$连接)。
静态variables示例:假装我们有一个数据库类,只有一个成员variables:static $ num_connections; 现在,把这个在构造函数中:
function __construct() { if(!isset $num_connections || $num_connections==null) { $num_connections=0; } else { $num_connections++; } }
正如对象具有构造函数一样,它们也具有析构函数,当对象死亡或未被设置时,
function __destruct() { $num_connections--; }
每当我们创build一个新的实例,它会增加我们的连接计数器。 每次我们销毁或停止使用一个实例,它都会减less连接计数器。 通过这种方式,我们可以监视我们使用的数据库对象的实例的数量:
echo DB::num_connections;
由于$ num_connections是静态的(共享的),它将反映活动数据库对象的总数。 您可能已经看到这种技术用于在数据库类的所有实例之间共享数据库连接。 这样做是因为创build数据库连接需要很长时间,所以最好创build一个,然后共享(这被称为Singleton模式)。
静态方法(即公共静态View :: format_phone_number($数字))可以使用没有首先实例化其中的一个对象(即他们不内部引用$ this)。
静态方法示例:
public static function prettyName($first_name, $last_name) { echo ucfirst($first_name).' '.ucfirst($last_name); } echo Person::prettyName($derek->first_name, $derek->last_name);
正如你所看到的,公共静态函数prettyName对这个对象一无所知。 它只是处理你传入的参数,就像一个不属于对象的普通函数。 那么,为什么要打扰呢,如果我们能把它作为对象的一部分呢?
- 首先,将对象附加到对象上有助于保持组织的有序性,以便知道在哪里find对象。
- 其次,它可以防止命名冲突。 在一个大项目中,你可能会有两个开发者创buildgetName()函数。 如果创build了一个ClassName1 :: getName(),另一个创build了ClassName2 :: getName(),那完全没有问题。 没有冲突。 耶静态方法!
SELF ::如果您要在具有要引用的静态方法的对象之外进行编码,则必须使用对象的名称View :: format_phone_number($ phone_number)来调用它。 如果要在具有要引用的静态方法的对象中进行编码,则可以使用对象的名称View :: format_phone_number($ pn),或者可以使用self :: format_phone_number($ pn)快捷方式
静态variables也是如此: 例如: View :: templates_path vs self :: templates_path
在DB类内部,如果我们引用了其他对象的静态方法,我们将使用该对象的名称: 例如: Session :: getUsersOnline();
但是,如果DB类想引用它自己的静态variables,它只会说self: 例如: self :: connection;
希望有助于清理事情:)
从这个博客文章 :
self
指的是现在的阶级self
可以用来调用静态函数和引用静态成员variablesself
可以在静态函数里面使用self
也可以绕过vtable来closures多态行为$this
引用当前对象$this
可以用来调用静态函数$this
不应该被用来调用静态成员variables。 用self
来代替。$this
不能在静态函数中使用
在类定义中,$ this指向当前对象,而self指向当前类。
有必要使用self引用一个类元素,并使用$ this引用一个对象元素。
self::STAT // refer to a constant value self::$stat // static variable $this->stat // refer to an object variable
在PHP中,您使用self关键字来访问静态属性和方法。
问题是你可以在任何地方用self::method()
replace$this->method()
,不pipemethod()
是否声明为static。 那么你应该使用哪一个?
考虑这个代码:
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::who()
将总是输出“parent”,而$this->who()
将取决于对象具有的类。
现在我们可以看到,self指向被调用的类,而$this
指的是当前对象的类 。
所以,只有当$this
不可用时,或者当您不希望允许后代类覆盖当前方法时,才应使用self。
下面是非静态和静态成员variables正确使用$ this和self的示例:
<?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(); ?>
根据http://www.php.net/manual/en/language.oop5.static.php没有$ self。 对于引用类(对象)的当前实例以及可以用来引用类的静态成员的self,只有$ this。 对象实例和类之间的区别在这里发挥作用。
我相信问题不在于是否可以通过调用ClassName :: staticMember来调用该类的静态成员。 问题是使用self :: classmember和$ this-> classmember有什么区别。
例如,下面的两个例子都没有任何错误,不pipe你使用self ::还是$ this->
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引用当前对象。 你可以使用静态而不是自我。 看例子:
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();
输出:父母的孩子
- 对象指针$ this引用当前对象。
- 类的值“static”是指当前对象。
- 类的值“self”是指它在其中定义的确切类。
- 类值“父”指的是它所在的确切类的父类。
看下面的例子显示重载。
<?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"
大多数时候你想引用当前类,这就是为什么你使用static
或$this
。 然而,有时候你需要 self
因为你想要原来的类,而不pipe它是什么。 (很,很less)
当self
与::
运算符一起使用时,它指向当前类,这可以在静态和非静态上下文中完成。 $this
指的是对象本身。 另外,使用$this
来调用静态方法(而不是引用字段)是完全合法的。
这里没有人谈论演出,这是我做的一个小基准(5.6):
Name | Time | Percent ----------|---------|--------- $this-> | 0.99163 | 106.23% self:: | 0.96912 | 103.82% static:: | 0.93348 | 100%
这些是200万次运行的结果,这里是我使用的代码:
<?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();
$this
refers to the current class object, self
refers to the current class (Not object). The class is the blueprint of the object. So you define a class, but you construct objects.
So in other words, use self for static
and this for none-static members or methods
.
also in child/parent scenario self / parent
is mostly used to identified child and parent class members and methods.
Additionally since $this::
has not been discussed yet.
For informational purposes only, as of PHP 5.3 when dealing with instantiated objects to get the current scope value, as opposed to using static::
, one can alternatively use $this::
like so.
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
Using the code above is not common or recommended practice, but is simply to illustrate its usage, and is to act as more of a "Did you know?" in reference to the original poster's question.
It also represents the usage of $object::CONSTANT
for example echo $foo::NAME;
as opposed to $this::NAME;
Use 'self' if you want to call a method of a class without creating an object/instance of that class, thus saving RAM (sometimes use self for that purpose). In other words, it is actually calling a method statically. Use 'this' for object perspective.
Case 1: Use self
can be used for class constants
class classA { const FIXED_NUMBER = 4; self::POUNDS_TO_KILOGRAMS }
If you want to call it outside of the class, use classA::POUNDS_TO_KILOGRAMS
to access the constants
Case 2: For static properties
class classC { public function __construct() { self::$_counter++; $this->num = self::$_counter; } }
According to php.net there are three special keywords in this context: self
, parent
and static
. They are used to access properties or methods from inside the class definition.
$this
, on the other hand, is used to call an instance and methods of any class as long as that class is accessible.