提问人:Casey Watson 提问时间:9/30/2008 最后编辑:Peter MortensenCasey Watson 更新时间:6/11/2023 访问量:825068
什么时候应该使用“self”而不是“$this”?
When should I use 'self' over '$this'?
答:
根据 Static Keyword,没有任何 .只有 ,用于引用类(对象)的当前实例,而 ,可用于引用类的静态成员。对象实例和类之间的区别在这里起作用。$self
$this
self
评论
简答
用于指代当前 对象。用于指代 当前类。换言之,用于非静态成员, 用于静态成员。
$this
self
$this->member
self::$member
完整答案
下面是正确使用非静态和静态成员变量的示例:$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
<?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();
?>
下面是通过 for 成员函数来抑制多态行为的示例: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();
?>
这个想法是调用当前对象的确切类型的成员函数。如果对象是 ,则调用 。如果对象为 ,则调用 。但是使用 self::foo(),总是被调用。
$this->foo()
foo()
type X
X::foo()
type Y
Y::foo()
X::foo()
从 http://www.phpbuilder.com/board/showthread.php?t=10354489:
由 http://board.phpbuilder.com/member.php?145249-laserlight 提供
评论
self
::
$this
$this::
self
(not $self) 是指类的类型,而是指类的当前实例。 用于静态成员函数,以允许您访问静态成员变量。 用于非静态成员函数,并且是对调用成员函数的类的实例的引用。$this
self
$this
因为是一个对象,所以你可以像这样使用它:this
$this->member
因为 is 不是对象,所以它基本上是自动引用当前类的类型。您可以像这样使用它:self
self::member
评论
class Test { ... }
int
string
DateTime
$x = new Test
$x
Test
$this->
用于引用类的变量(成员变量)或方法的特定实例。
Example:
$derek = new Person();
$derek现在是 Person 的特定实例。 每个人都有first_name和last_name,但$derek都有特定的first_name和last_name(德里克·马丁)。在$derek实例中,我们可以将它们称为 $this->first_name 和 $this->last_name
ClassName:: 用于指代该类型的类及其静态变量、静态方法。如果有帮助,你可以在心理上用“共享”代替“静态”这个词。因为它们是共享的,所以它们不能引用$this,而是指特定实例(未共享)。静态变量(即静态 $db_connection)可以在一类对象的所有实例之间共享。例如,所有数据库对象共享一个连接(静态$connection)。
静态变量示例:假设我们有一个带有单个成员变量的数据库类:static $num_connections; 现在,将其放入构造函数中:
function __construct()
{
if(!isset $num_connections || $num_connections==null)
{
$num_connections=0;
}
else
{
$num_connections++;
}
}
正如对象具有构造函数一样,它们也有析构函数,这些析构函数在对象死亡或未设置时执行:
function __destruct()
{
$num_connections--;
}
每次我们创建一个新实例时,它都会将我们的连接计数器增加 1。每次我们销毁或停止使用实例时,它都会将连接计数器减少一个。通过这种方式,我们可以监控我们正在使用的数据库对象的实例数:
echo DB::num_connections;
由于 $num_connections 是静态的(共享),因此它将反映活动数据库对象的总数。您可能已经看到此技术用于在数据库类的所有实例之间共享数据库连接。这样做是因为创建数据库连接需要很长时间,因此最好只创建一个并共享它(这称为单例模式)。
静态方法(即公共静态视图::format_phone_number($digits))可以在不首先实例化其中一个对象的情况下使用(即它们在内部不引用$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 对对象一无所知。它只是使用您传入的参数,就像不属于对象的普通函数一样。那么,如果我们能把它作为对象的一部分,为什么还要麻烦呢?
- 首先,将函数附加到对象有助于保持事物井井有条,以便您知道在哪里可以找到它们。
- 其次,它可以防止命名冲突。在一个大项目中,你可能会有两个开发人员创建 getName() 函数。如果一个创建 ClassName1::getName(),另一个创建 ClassName2::getName(),则完全没有问题。没有冲突。是的静态方法!
自我::如果要在具有要引用的静态方法的对象外部进行编码,则必须使用对象的名称 View::format_phone_number($phone_number); 如果要在具有要引用的静态方法的对象内进行编码,则可以使用对象的名称 View::format_phone_number($pn),也可以使用 self::format_phone_number($pn) 快捷方式
静态变量也是如此:示例:View::templates_path 与 self::templates_path
在 DB 类中,如果我们引用其他对象的静态方法,我们将使用该对象的名称: 示例:Session::getUsersOnline();
但是,如果 DB 类想要引用它自己的静态变量,它只会说 self: 示例:self::connection;
评论
$
self::$templates_path
我相信问题不在于你是否可以通过调用来调用类的静态成员。问题是使用 和 之间有什么区别。ClassName::staticMember
self::classmember
$this->classmember
例如,以下两个示例都可以正常工作,而不会出现任何错误,无论您使用 还是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;
}
}
评论
Fatal error: Access to undeclared static property: Person::$name in D:\LAMP\www\test.php on line 16
关键字 self 不仅仅指“当前类”,至少不会将您限制为静态成员。在非静态成员的上下文中,还提供了一种绕过当前对象的 vtable(参见 vtable 上的 wiki)的方法。就像你可以用来调用一个函数的父版本一样,你也可以调用一个方法的当前类的实现。self
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()
使用指针,因此调用 vtable 来调用 . 使用 ,因此不使用 vtable,而是调用 vtable。在这两种情况下,我们都在处理实例化对象的方法,并且可以访问被调用函数中的指针。$this
Geek::getTitle()
sayGoodbye()
self::getTitle()
Person::getTitle()
$this
评论
self
static
$this::
$this::
$this->
self::
static::
不要使用 self::
。使用 static::
*
自我还有另一个方面::值得一提。令人讨厌的是,self::
指的是定义点的范围,而不是执行点的范围。考虑这个包含两种方法的简单类:
class Person
{
public static function status()
{
self::getStatus();
}
protected static function getStatus()
{
echo "Person is alive";
}
}
如果我们打电话,我们会看到“人还活着”。现在考虑一下,当我们创建一个继承自这个的类时会发生什么:Person::status()
class Deceased extends Person
{
protected static function getStatus()
{
echo "Person is deceased";
}
}
打电话时,我们希望看到“人已死亡”。但是,我们看到“Person is alive”,因为定义调用时,作用域包含原始方法定义。Deceased::status()
self::getStatus()
PHP 5.3 有一个解决方案。static::
resolution 运算符实现了“后期静态绑定”,这是一种奇特的说法,即它绑定到所调用类的作用域。将行更改为,结果就是您所期望的。在旧版本的 PHP 中,您必须找到一个 kludge 来执行此操作。status()
static::getStatus()
参见 PHP 文档
所以要回答这个问题,而不是像问的那样......
$this->
引用当前对象(类的实例),而引用类。static::
评论
getStatus
self::
MyClass::
以下是正确使用 $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();
?>
当与运算符一起使用时,它引用当前类,这可以在静态和非静态上下文中完成。 指对象本身。此外,用于调用静态方法(但不能引用字段)是完全合法的。self
::
$this
$this
- 对象指针是指当前对象。
$this
- 类值引用当前对象。
static
- 类值是指定义它的确切类。
self
- 类值是指定义它的确切类的父级。
parent
请参阅以下示例,该示例显示了重载。
<?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"
大多数时候,您希望引用当前类,这就是您使用 or 的原因。但是,有时您需要,因为无论扩展什么,您都需要原始类。(非常非常罕见)static
$this
self
如果要调用某个类的方法而不创建该类的对象/实例,从而节省 RAM(有时为此目的使用 self),请使用该函数。换句话说,它实际上是静态调用方法。用于对象透视。self
this
在类定义中,引用当前对象,而引用当前类。$this
self
必须使用 来引用类元素,并使用 来引用对象元素。self
$this
self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable
从这篇博文:
self
指当前类self
可用于调用静态函数和引用静态成员变量self
可以在静态函数中使用self
还可以通过绕过 vtable 来关闭多态行为$this
指当前对象$this
可用于调用静态函数$this
不应用于调用静态成员变量。请改用。self
$this
不能在静态函数内部使用
为了真正理解我们在谈论什么,我们需要在概念和实践层面上真正深入研究正在发生的事情。我真的不觉得任何答案都恰当地做到了这一点,所以这是我的尝试。self
$this
让我们先来谈谈什么是类和对象。
类和对象,从概念上讲
那么,什么是类呢?很多人将其定义为对象的蓝图或模板。事实上,你可以在这里阅读更多关于PHP中的类。在某种程度上,这就是它的真实面目。让我们看一个类:
class Person {
public $name = 'my name';
public function sayHello() {
echo "Hello";
}
}
正如你所知道的,该类上有一个属性叫做,方法(函数)叫做。$name
sayHello()
需要注意的是,该类是一个静态结构。这意味着类一旦定义,在你看到的任何地方都是相同的。Person
另一方面,对象是所谓的类实例。这意味着我们采用类的“蓝图”,并使用它来制作动态副本。此副本现在专门绑定到它所存储的变量。因此,对实例的任何更改都是该实例的本地更改。
$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"
我们使用运算符创建一个类的新实例。new
因此,我们说类是全局结构,对象是局部结构。不要担心这个有趣的语法,我们稍后会介绍它。->
我们应该讨论的另一件事是,我们可以检查一个实例是否是一个特定的类:如果实例是使用该类创建的,则返回一个布尔值,或者是 的子类。instanceof
$bob instanceof Person
$bob
Person
Person
定义状态
因此,让我们深入研究一下类实际包含的内容。一个类包含 5 种类型的“事物”:
属性 - 将这些视为每个实例将包含的变量。
class Foo { public $bar = 1; }
静态属性 - 将这些属性视为在类级别共享的变量。这意味着它们永远不会被每个实例复制。
class Foo { public static $bar = 1; }
方法 - 这些是每个实例将包含(并在实例上运行)的函数。
class Foo { public function bar() {} }
静态方法 - 这些是在整个类中共享的函数。它们不对实例进行操作,而只对静态属性进行操作。
class Foo { public static function bar() {} }
常量 - 类解析的常量。这里不再深入讨论,但为了完整起见,请补充:
class Foo { const BAR = 1; }
因此,基本上,我们使用有关静态的“提示”将信息存储在类和对象容器上,这些“提示”标识信息是共享的(因此是静态的)还是非共享的(因此是动态的)。
状态和方法
在方法内部,对象的实例由变量表示。该对象的当前状态就在那里,改变(更改)任何属性都将导致对该实例(但不是其他实例)的更改。$this
如果静态调用方法,则不会定义变量。这是因为没有与静态调用关联的实例。$this
这里有趣的是静态调用是如何进行的。因此,让我们谈谈我们如何访问状态:
访问状态
因此,现在我们已经存储了该状态,我们需要访问它。这可能会变得有点棘手(或不止一点点),所以让我们把它分成两个观点:从实例/类外部(比如从普通函数调用,或从全局范围),和实例/类内部(从对象上的方法内部)。
从实例/类外部
从实例/类的外部来看,我们的规则非常简单且可预测。我们有两个运算符,每个运算符都会立即告诉我们,我们是在处理实例还是类静态:
->
- object-operator - 当我们访问实例时,始终使用此选项。$bob = new Person; echo $bob->name;
需要注意的是,调用没有意义(因为是一个类,而不是一个实例)。因此,这是一个解析错误。
Person->foo
Person
::
- scope-resolution-operator - 这始终用于访问 Class 静态属性或方法。echo Foo::bar()
此外,我们可以以相同的方式在对象上调用静态方法:
echo $foo::bar()
需要注意的是,当我们从外部执行此操作时,对象的实例在方法中是隐藏的。这意味着它与运行完全相同:
bar()
$class = get_class($foo); $class::bar();
因此,未在静态调用中定义。$this
从实例/类内部
这里的情况发生了一些变化。使用相同的运算符,但它们的含义变得非常模糊。
对象运算符仍用于调用对象的实例状态。->
class Foo {
public $a = 1;
public function bar() {
return $this->a;
}
}
使用 object-operator: 调用 上的方法(实例 )将导致实例的 版本为 。bar()
$foo
Foo
$foo->bar()
$a
这就是我们所期望的。
但运算符的含义发生了变化。这取决于对当前函数的调用的上下文:::
在静态上下文中
在静态上下文中,使用进行的任何调用也将是静态的。让我们看一个例子:
::
class Foo { public function bar() { return Foo::baz(); } public function baz() { return isset($this); } }
调用将静态调用该方法,因此不会填充。值得注意的是,在最新版本的 PHP (5.3+) 中,这将触发一个错误,因为我们静态调用非静态方法。
Foo::bar()
baz()
$this
E_STRICT
在实例上下文中
另一方面,在实例上下文中,使用的调用取决于调用的接收方(我们正在调用的方法)。如果该方法定义为 ,则它将使用静态调用。如果不是,它将转发实例信息。
::
static
因此,查看上面的代码,调用将返回 ,因为“静态”调用发生在实例上下文中。
$foo->bar()
true
有意义?我不这么认为。这令人困惑。
快捷键关键字
因为使用类名将所有内容联系在一起是相当肮脏的,PHP 提供了 3 个基本的“快捷方式”关键字来使范围解析更容易。
self
- 这是指当前类名。因此,与类(其上的任何方法)相同。self::baz()
Foo::baz()
Foo
parent
- 这是指当前类的父类。static
- 这是指被调用的类。由于继承,子类可以重写方法和静态属性。因此,使用而不是类名来调用它们可以让我们解析调用的来源,而不是当前级别。static
例子
理解这一点的最简单方法是开始查看一些示例。让我们选择一个类:
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();
}
}
现在,我们也在这里研究继承。暂时忽略这是一个糟糕的对象模型,但让我们看看当我们使用它时会发生什么:
$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)
现在这里真的很奇怪。我们正在调用一个不同的类,但传递给该方法的是 的实例。$this
Foo::isFoo()
$bar
这可能会导致各种错误和概念上的WTF-ery。因此,我强烈建议在实例方法中避免使用运算符,除了这三个虚拟的“快捷方式”关键字(、 和 )。::
static
self
parent
警告词 #2
请注意,静态方法和属性由所有人共享。这使得它们基本上是全局变量。与全局变量相同的所有问题。因此,我非常犹豫是否将信息存储在静态方法/属性中,除非您对它是真正的全局感到满意。
警告词 #3
通常,您需要使用 而不是 来使用所谓的 Late-Static-Binding。但请注意,它们不是一回事,所以说“总是使用而不是”真的是短视的。相反,停下来想想你要进行的调用,并想想你是否希望子类能够覆盖该静态解析的调用。static
self
static
self
TL/DR (英语)
太糟糕了,回去读一读。它可能太长了,但它很长,因为这是一个复杂的话题
TL/DR #2
好的,很好。简而言之,用于引用类中的当前类名,其中 as 表示当前对象实例。请注意,这是一个复制/粘贴快捷方式。您可以安全地将其替换为您的类名,它会正常工作。但是一个动态变量,无法提前确定(甚至可能不是你的类)。self
$this
self
$this
TL/DR #3
如果使用了对象运算符 (),那么你总是知道你正在处理一个实例。如果使用 scope-resolution-operator (),则需要有关上下文的更多信息(我们是否已经处于对象上下文中?我们是否在物体之外?等)。->
::
评论
$this
$this
引用当前类对象,并引用当前类(Not object)。类是对象的蓝图。因此,您定义了一个类,但是您构造了对象。self
因此,换句话说,使用 和 .self for static
this for none-static members or methods
此外,在子类/父类方案中,主要用于标识子类和父类成员和方法。self / parent
此外,此后尚未讨论。$this::
仅供参考,从 PHP 5.3 开始,在处理实例化对象以获取当前范围值时,而不是使用 ,也可以这样使用。static::
$this::
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
使用上面的代码并不常见或推荐,而只是为了说明它的用法,并且更像是“你知道吗?”,指的是原始发帖人的问题。
它还表示例如,与$object::CONSTANT
echo $foo::NAME;
$this::NAME;
在 PHP 中,使用 self 关键字来访问静态属性和方法。
问题是你可以用任何地方替换,无论是否声明为静态。那么你应该使用哪一个呢?$this->method()
self::method()
method()
请考虑以下代码:
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();
在此示例中,将始终输出 'parent',而 将取决于对象具有的类。self::who()
$this->who()
现在我们可以看到 self 指的是调用它的类,而 self 指的是当前对象的类。$this
因此,仅当不可用或不想允许后代类覆盖当前方法时,才应使用 self。$this
这是一个小的基准测试(repl.it 上的 7.2.24):
Speed (in seconds) Percentage
$this-> 0.91760206222534 100
self:: 1.0047659873962 109.49909865716
static:: 0.98066782951355 106.87288857386
4 000 000 次运行的结果。结论:没关系。这是我使用的代码:
<?php
class Foo
{
public function calling_this() { $this->called(); }
public function calling_self() { self::called(); }
public function calling_static() { static::called(); }
public static function called() {}
}
$foo = new Foo();
$n = 4000000;
$times = [];
// warmup
for ($i = 0; $i < $n; $i++) { $foo->calling_this(); }
for ($i = 0; $i < $n; $i++) { $foo->calling_self(); }
for ($i = 0; $i < $n; $i++) { $foo->calling_static(); }
$start = microtime(true);
for ($i = 0; $i < $n; $i++) { $foo->calling_this(); }
$times["this"] = microtime(true)-$start;
$start = microtime(true);
for ($i = 0; $i < $n; $i++) { $foo->calling_self(); }
$times["self"] = microtime(true)-$start;
$start = microtime(true);
for ($i = 0; $i < $n; $i++) { $foo->calling_static(); }
$times["static"] = microtime(true)-$start;
$min = min($times);
echo $times["this"] . "\t" . ($times["this"] / $min)*100 . "\n";
echo $times["self"] . "\t" . ($times["self"] / $min)*100 . "\n";
echo $times["static"] . "\t" . ($times["static"] / $min)*100 . "\n";
评论
1 / 2e9 s = 0.5 ns
use
根据 php.net 在此上下文中有三个特殊关键字:和 。它们用于从类定义内部访问属性或方法。self
parent
static
$this
另一方面,用于调用任何类的实例和方法,只要该类是可访问的。
self
指当前类(在其中调用它),
$this
指当前对象。
您可以使用 static 代替 self。
请参阅示例:
class ParentClass {
function test() {
self::which(); // Outputs 'parent'
$this->which(); // Outputs 'child'
}
function which() {
echo 'parent';
}
}
class ChildClass extends ParentClass {
function which() {
echo 'child';
}
}
$obj = new ChildClass();
$obj->test();
输出:
parent
child
案例 1:Use 可用于类常量self
class classA { const FIXED_NUMBER = 4; self::POUNDS_TO_KILOGRAMS }
如果要在类外部调用它,请使用 to 访问常量classA::POUNDS_TO_KILOGRAMS
案例 2:对于静态属性
class classC { public function __construct() { self::$_counter++; $this->num = self::$_counter; } }
我遇到了同样的问题,简单的答案是:
$this
需要类的实例self::
不
每当您使用静态方法或静态属性并希望在不实例化类对象的情况下调用它们时,您都需要使用来调用它们,因为始终需要创建一个对象。self:
$this
自我::用于当前类的关键字,基本上用于访问静态成员、方法和常量。但在$this的情况下,不能调用静态成员、方法和函数。
可以在另一个类中使用 self:: 关键字并访问静态成员、方法和常量。何时从父类扩展,如果是 $this 关键字,则相同。当另一个类将从父类扩展时,您可以访问另一个类中的非静态成员、方法和函数。
下面给出的代码是 self:: 和 $this 关键字的示例。只需将代码复制并粘贴到代码文件中,即可查看输出。
class cars{
var $doors = 4;
static $car_wheel = 4;
public function car_features(){
echo $this->doors . " Doors <br>";
echo self::$car_wheel . " Wheels <br>";
}
}
class spec extends cars{
function car_spec(){
print(self::$car_wheel . " Doors <br>");
print($this->doors . " Wheels <br>");
}
}
/********Parent class output*********/
$car = new cars;
print_r($car->car_features());
echo "------------------------<br>";
/********Extend class from another class output**********/
$car_spec_show = new spec;
print($car_spec_show->car_spec());
虽然这是一个老问题,但作为一个新手,我发现以下比较很有用。特别是与 一起使用所需的规则和语法。self
$this
// A. Definitions
// Three classes bar1 for parallel use, and bar2 and bar3 for linear use;
class bar1 {
// Class bar1 to use the object method "$this",
// to create multiple parallel instances;
public $foo = 111; // Property "$foo" set without "static" keyword;
// because we will be using the object method "$this",
// to create multiple (unique and fresh) instances;
public function getfoo() {
return $this->foo; // Function "getfoo" returns the value of property "foo";
// While calling the property using "$this", no "$" symbol is used;
// By calling our class "bar1" using "$this" instead of "self",
// we can use on multiple instances;
}
public function setfoo($foo) {
$this->foo = $foo; // Function "setfoo" sets the value of property "foo";
// While calling the property using "$this", no "$" symbol is used;
// By calling our class "bar1" using "$this" instead of "self",
// we can use on multiple instances;
}
}
class bar2 {
// Class bar2 to use the static method "self" to use as single linear instance;
// Note the use of "::" (scope resolution operator) instead of object call "->"
public static $foo = 111; // Property "$foo" set with "static" keyword;
// because we will be using the static method "self" to use as single instance;
public static function getfoo() {
return self::$foo; // Function "getfoo" returns the value of property "foo";
// While calling the property using "self", "$" symbol is necessary;
// We are calling our class "bar2" using "self" instead of "$this",
// because we are using static method "self" to use as single instance;
}
public static function setfoo($foo) {
self::$foo = $foo; // Function "setfoo" sets the value of property "foo";
// While calling the property using "self", "$" symbol is necessary;
// We are calling our class "bar2" using "self" instead of $this,
// because we are using static method "self" to use as single instance;
}
}
class bar3 {
// Class bar3 is same as bar2 and uses the static method "self",
// except it sets the property "$foo" using "__construct" constructor method;
// so it can be used as a single linear instance,
// which can be optionally reset/reinitialized;
public static $foo; // Property "$foo" initialized with "static" keyword;
// No value is set here because we are setting it using "__construct" instead;
public function __construct() { // "__construct" will set the property values
self::$foo = 111;
}
public static function getfoo() {
return self::$foo;
}
public static function setfoo($foo) {
self::$foo = $foo;
}
}
// B. Tests
// B.1 Object method; Parallel instances $x and $y;
$x = new bar1(); // Fresh instance $x
echo $x->getfoo().PHP_EOL; // Output: 111
$x->setfoo(123); // Updated instance $x
echo $x->getfoo().PHP_EOL.PHP_EOL; // Output: 123
$y = new bar1(); // Fresh instance $y
echo $y->getfoo().PHP_EOL; // Output: 111
$y->setfoo(143); // Updated instance $y
echo $y->getfoo().PHP_EOL.PHP_EOL; // Output: 143
// B.2 Static method; Single linear instance;
new bar2(); // Not a fresh instance; Can be omitted;
echo bar2::getfoo().PHP_EOL; // Output: 111
bar2::setfoo(123); // Updated the same static instance
echo bar2::getfoo().PHP_EOL.PHP_EOL; // Output: 123
new bar2(); // Not a fresh instance; Can be omitted;
echo bar2::getfoo().PHP_EOL; // Output: 123
bar2::setfoo(143); // Updated the same static instance
echo bar2::getfoo().PHP_EOL.PHP_EOL; // Output: 143
// B.3 Static method using __construct; Single linear yet re-settable instance;
new bar3(); // Resets into a fresh instance; Omitting this line will reuse old instance;
echo bar3::getfoo().PHP_EOL; // Output: 111
bar3::setfoo(123); // Updated the same static instance
echo bar3::getfoo().PHP_EOL.PHP_EOL; // Output: 123
new bar3(); // Resets into a fresh instance; Omitting this line will reuse old instance;
echo bar3::getfoo().PHP_EOL; // Output: 111
bar3::setfoo(143); // Updated the same static instance
echo bar3::getfoo().PHP_EOL.PHP_EOL; // Output: 143
评论