静态关键字

提示

此页面描述了使用 static 关键字定义静态方法和属性。 static 也可以用于 定义静态变量定义静态匿名函数 以及 延迟静态绑定。有关 static 的这些含义,请参阅这些页面。

将类属性或方法声明为静态,使它们无需实例化类即可访问。这些也可以在实例化的类对象中静态访问。

静态方法

由于静态方法可以在没有创建对象实例的情况下调用,因此在声明为静态的方法内部,伪变量 $this 不可使用。

警告

静态地调用非静态方法会抛出 Error

在 PHP 8.0.0 之前,静态地调用非静态方法已被弃用,并会生成 E_DEPRECATED 警告。

示例 #1 静态方法示例

<?php
class Foo {
public static function
aStaticMethod() {
// ...
}
}

Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod();
?>

静态属性

静态属性使用 范围解析运算符 (::) 访问,不能通过对象运算符 (->) 访问。

可以使用变量来引用类。变量的值不能是关键字(例如 selfparentstatic)。

示例 #2 静态属性示例

<?php
class Foo
{
public static
$my_static = 'foo';

public function
staticValue() {
return
self::$my_static;
}
}

class
Bar extends Foo
{
public function
fooStatic() {
return
parent::$my_static;
}
}


print
Foo::$my_static . "\n";

$foo = new Foo();
print
$foo->staticValue() . "\n";
print
$foo->my_static . "\n"; // Undefined "Property" my_static

print $foo::$my_static . "\n";
$classname = 'Foo';
print
$classname::$my_static . "\n";

print
Bar::$my_static . "\n";
$bar = new Bar();
print
$bar->fooStatic() . "\n";
?>

在 PHP 8 中,上面示例的输出类似于

foo
foo

Notice: Accessing static property Foo::$my_static as non static in /in/V0Rvv on line 23

Warning: Undefined property: Foo::$my_static in /in/V0Rvv on line 23

foo
foo
foo
foo
添加注释

用户贡献的注释 28 个注释

232
inkredibl
16 年前
请注意,如果您正在寻找用于在函数(或方法)内部声明静态变量的静态关键字用法,那么您应该阅读“变量/变量范围”。我个人直到最近才发现我的 PHP 知识中的这个空白,不得不去谷歌搜索才找到它。我认为此页面应该有一个指向静态函数变量的“另请参见”链接。
https://php.net/manual/en/language.variables.scope.php
154
payal001 at gmail dot com
13 年前
这里静态访问的属性优先于调用它的类的属性。而 self 关键字仅强制使用当前类。请参考以下示例

<?php
class a{

static protected
$test="class a";

public function
static_test(){

echo static::
$test; // 结果为 class b
echo self::$test; // 结果为 class a

}

}

class
b extends a{

static protected
$test="class b";

}

$obj = new b();
$obj->static_test();
?>
33
artekpuck at gmail dot com
6 年前
值得一提的是,每个静态变量只有一个值,对所有实例都是相同的
8
sideshowAnthony at googlemail dot com
8 年前
静态关键字仍然可以在函数内部使用(以非 OOP 方式)。因此,如果您需要一个与您的类一起存储的值,但它非常特定于函数,您可以使用它

class aclass {
public static function b(){
static $d=12; // 仅在第一次函数调用时设置为 12
$d+=12;
return "$d\n";
}
}

echo aclass::b(); //24
echo aclass::b(); //36
echo aclass::b(); //48
echo aclass::$d; // 致命错误
6
rahul dot anand77 at gmail dot com
8 年前
要检查类中声明的方法是否是静态的,您可以使用以下代码。PHP5 具有反射类,非常有用。

try {
$method = new ReflectionMethod( 'className::methodName );
if ( $method->isStatic() )
{
// 方法是静态的。
}
}
catch ( ReflectionException $e )
{
// 方法不存在
echo $e->getMessage();
}

*您可以在 https://php.net/manual/en/class.reflectionclass.php 上阅读有关反射类的更多信息
12
vinayak dot anivase at gmail dot com
6 年前
这也可以

class Foo {
public static $bar = 'a static property';
}

$baz = (new Foo)::$bar;
echo $baz;
11
Anonymous
19 年前
您误解了继承的含义:从基类继承时,成员不会被复制。成员通过继承共享,并且派生类可以根据可见性(公用、受保护、私有)访问它们。

静态成员和非静态成员之间的区别在于,非静态成员与类的实例绑定,而静态成员与类绑定,而不是与特定实例绑定。
也就是说,静态成员由类的所有实例共享,而非静态成员对于类的每个实例都存在。

因此,在您的示例中,静态属性根据面向对象概念的原则具有正确的值。
类 Base
{
public $a;
public static $b;
}

类 Derived 扩展 Base
{
public function __construct()
{
$this->a = 0;
parent::$b = 0;
}
public function f()
{
$this->a++;
parent::$b++;
}
}

$i1 = new Derived;
$i2 = new Derived;

$i1->f();
echo $i1->a, ' ', Derived::$b, "\n";
$i2->f();
echo $i2->a, ' ', Derived::$b, "\n";

输出
1 1
1 2
9
Anonymous
10 年前
需要注意的是,在“示例 #2”中,您也可以像这样调用可变定义的静态方法

<?php
class Foo {
public static function
aStaticMethod() {
// ...
}
}

$classname = 'Foo';
$methodname = 'aStaticMethod';
$classname::{$methodname}(); // 从 PHP 5.3.0 开始,我相信
?>
7
ASchmidt at Anamera dot net
5 年前
了解类继承上下文中静态属性的行为非常重要

- 在父类和子类中定义的静态属性将为每个类保存不同的值。在子方法内部正确使用 self:: 和 static:: 至关重要,以引用预期的静态属性。

- 仅在父类中定义的静态属性将共享一个公共值。

<?php
declare(strict_types=1);

class
staticparent {
static
$parent_only;
static
$both_distinct;

function
__construct() {
static::
$parent_only = 'fromparent';
static::
$both_distinct = 'fromparent';
}
}

class
staticchild extends staticparent {
static
$child_only;
static
$both_distinct;

function
__construct() {
static::
$parent_only = 'fromchild';
static::
$both_distinct = 'fromchild';
static::
$child_only = 'fromchild';
}
}

$a = new staticparent;
$a = new staticchild;

echo
'Parent: parent_only=', staticparent::$parent_only, ', both_distinct=', staticparent::$both_distinct, "<br/>\r\n";
echo
'Child: parent_only=', staticchild::$parent_only, ', both_distinct=', staticchild::$both_distinct, ', child_only=', staticchild::$child_only, "<br/>\r\n";
?>

将输出
Parent: parent_only=fromchild, both_distinct=fromparent
Child: parent_only=fromchild, both_distinct=fromchild, child_only=fromchild
11
davidn at xnet dot co dot nz
15 年前
静态变量在子类之间共享

<?php
class MyParent {

protected static
$variable;
}

class
Child1 extends MyParent {

function
set() {

self::$variable = 2;
}
}

class
Child2 extends MyParent {

function
show() {

echo(
self::$variable);
}
}

$c1 = new Child1();
$c1->set();
$c2 = new Child2();
$c2->show(); // 打印 2
?>
4
b1tchcakes
8 年前
<?php

trait t {
protected
$p;
public function
testMe() {echo 'static:'.static::class. ' // self:'.self::class ."\n";}
}

class
a { use t; }
class
b extends a {}

echo (new
a)->testMe();
echo (new
b)->testMe();

输出
static:a // self:t
static:b // self:t
11
aidan at php dot net
19 年前
要检查函数是静态调用还是非静态调用,您需要执行以下操作

<?php
function foo () {
$isStatic = !(isset($this) && get_class($this) == __CLASS__);
}
?>

更多信息请访问 (http://blog.phpdoc.info/archives/4-Schizophrenic-Methods.html).

(我将很快将其添加到手册中)。
11
webmaster at removethis dot weird-webdesign dot de
14 年前
在 PHP 5.2.x 或更早版本中,您可能会遇到在子类中初始化静态变量的问题,因为缺少延迟静态绑定

<?php
class A {
protected static
$a;

public static function
init($value) { self::$a = $value; }
public static function
getA() { return self::$a; }
}

class
B extends A {
protected static
$a; // 重新定义 $a 用于自身使用

// 继承 init() 方法
public static function getA() { return self::$a; }
}

B::init('lala');
echo
'A::$a = '.A::getA().'; B::$a = '.B::getA();
?>

这将输出
A::$a = lala; B::$a =

如果 init() 方法对于(几乎)所有子类都相同,则无需在每个子类中实现 init(),从而产生冗余代码。

解决方案 1
将所有内容转换为非静态。但:这将在类的每个对象上产生冗余数据。

解决方案 2
将类 A 上的静态 $a 转换为数组,使用子类的类名作为索引。通过这样做,您也不必为子类重新定义 $a,并且超类的 $a 可以是私有的。

DataRecord 类上的简短示例,没有错误检查

<?php
抽象类 DataRecord {
private static
$db; // MySQLi-连接,所有子类相同
private static $table = array(); // 子类表的数组

public static function init($classname, $table, $db = false) {
if (!(
$db === false)) self::$db = $db;
self::$table[$classname] = $table;
}

public static function
getDB() { return self::$db; }
public static function
getTable($classname) { return self::$table[$classname]; }
}

class
UserDataRecord extends DataRecord {
public static function
fetchFromDB() {
$result = parent::getDB()->query('select * from '.parent::getTable('UserDataRecord').';');

// 等等 ...
return $result; // UserDataRecord 对象的数组
}
}

$db = new MySQLi(...);
UserDataRecord::init('UserDataRecord', 'users', $db);
$users = UserDataRecord::fetchFromDB();
?>

我希望这对某些需要在 PHP 5.2.x 服务器上运行的人有所帮助。当然,延迟静态绑定使这种解决方法过时了。
6
tolean_dj at yahoo dot com
13 年前
从 PHP 5.3 开始,您可以使用 static 关键字的新功能。这是一个抽象单例类的示例

<?php

抽象类 Singleton {

protected static
$_instance = NULL;

/**
* 防止直接创建对象
*/
final private function __construct() { }

/**
* 防止对象克隆
*/
final private function __clone() { }

/**
* 返回新的或现有的 Singleton 实例
* @return Singleton
*/
final public static function getInstance(){
if(
null !== static::$_instance){
return static::
$_instance;
}
static::
$_instance = new static();
return static::
$_instance;
}

}
?>
5
gratcypalma at gmail dot om
13 年前
<?php
class foo {
private static
$getInitial;

public static function
getInitial() {
if (
self::$getInitial == null)
self::$getInitial = new foo();
return
self::$getInitial;
}
}

foo::getInitial();

/*
这是使用具有静态方法的新类的示例。..
希望对您有所帮助
*/

?>
4
ssj dot narutovash at gmail dot com
16 年前
我注意到您不能在 HEREDOC 字符串中使用静态成员。以下代码

class A
{
public static $BLAH = "user";

function __construct()
{
echo <<<EOD
<h1>Hello {self::$BLAH}</h1>
EOD;
}
}

$blah = new A();

在源代码中产生以下内容

<h1>Hello {self::}</h1>

解决方法

在使用静态成员之前,将其存储在本地变量中,如下所示

class B
{
public static $BLAH = "user";

function __construct()
{
$blah = self::$BLAH;
echo <<<EOD
<h1>Hello {$blah}</h1>
EOD;
}
}

输出的源代码将是

<h1>Hello user</h1>
1
Jay Cain
14 年前
关于在类中初始化复杂的静态变量,您可以通过创建名为 init() 的静态函数并在类定义后立即调用它来模拟静态构造函数。

<?php
class Example {
private static
$a = "Hello";
private static
$b;

public static function
init() {
self::$b = self::$a . " World!";
}
}
Example::init();
?>
0
manishpatel2280 at gmail dot com
10 年前
在现实世界中,可以说当我们不想创建对象实例时,我们会使用静态方法。

例如...

validateEmail($email) {
if(T) return true;
return false;
}

// 这没有多大意义
$obj = new Validate();
$result = $obj->validateEmail($email);

// 这更有意义
$result = Validate::validateEmail($email);
1
michalf at ncac dot torun dot pl
19 年前
使用静态元素的继承在 php 中是一场噩梦。考虑以下代码

<?php
class BaseClass{
public static
$property;
}

class
DerivedClassOne extends BaseClass{
}

class
DerivedClassTwo extends BaseClass{
}

DerivedClassOne::$property = "foo";
DerivedClassTwo::$property = "bar";

echo
DerivedClassOne::$property; // 人们天真地会期待 "foo"...
?>

您会期望得到什么输出?"foo"?错了。它是 "bar"!!!静态变量不会被继承,它们指向 BaseClass::$property。

此时我认为继承在静态变量/方法的情况下不起作用真是太可惜了。请记住这一点,并在调试时节省您的时间。

此致 - michal
0
zerocool at gameinsde dot ru
15 年前
您好,以下是我简单的 Singleton 示例,我认为它对某些人可能有用。例如,您可以使用此模式连接到数据库。

<?php

class MySingleton
{
private static
$instance = null;

private function
__construct()
{
$this-> name = 'Freddy';

}

public static function
getInstance()
{
if(
self::$instance == null)
{
print
"Object created!<br>";
self::$instance = new self;

}

return
self::$instance;

}

public function
sayHello()
{
print
"Hello my name is {$this-> name}!<br>";

}

public function
setName($name)
{
$this-> name = $name;

}

}

//

$objA = MySingleton::getInstance(); // Object created!

$objA-> sayHello(); // Hello my name is Freddy!

$objA-> setName("Alex");

$objA-> sayHello(); // Hello my name is Alex!

$objB = MySingleton::getInstance();

$objB-> sayHello(); // Hello my name is Alex!

$objB-> setName("Bob");

$objA-> sayHello(); // Hello my name is Bob!

?>
-2
Mirco
13 年前
最简单的静态构造函数。

因为 php 没有静态构造函数,并且您可能希望初始化静态类变量,所以有一个简单的方法,只需在类定义后立即调用您自己的函数。

例如。

<?php
function Demonstration()
{
return
'This is the result of demonstration()';
}

class
MyStaticClass
{
//public static $MyStaticVar = Demonstration(); //!!! FAILS: syntax error
public static $MyStaticVar = null;

public static function
MyStaticInit()
{
//这是一个静态构造函数
//因为在函数中,所有操作都是允许的,包括使用其他函数初始化

self::$MyStaticVar = Demonstration();
}
}
MyStaticClass::MyStaticInit(); //调用静态构造函数

echo MyStaticClass::$MyStaticVar;
//This is the result of demonstration()
?>
-2
jkenigso at utk dot edu
10 年前
值得一提的是,静态变量(以下意义)会持久存在

<?php
class StaticVars
{
public static
$a=1;
}
$b=new StaticVars;
$c=new StaticVars;

echo
$b::$a; //输出 1
$c::$a=2;
echo
$b::$a; //输出 2!
?>

注意,$c::$a=2 改变了 $b::$a 的值,即使 $b 和 $c 是完全不同的对象。
-2
admin at shopinson dot com
3 年前
我使用实例化来直接访问静态属性。

一个简单的技巧,你可以应用(使用对象访问类中的静态属性)使用范围解析运算符
<?php
class Shopinson {
const
MY_CONSTANT = 'the value of MY_CONSTANT ';
}

class
Godwin extends Shopinson
{
public static
$myconstant = ' The Paamayim Nekudotayim or double-colon.';
public function
SaySomething(){
echo
parent::MY_CONSTANT .PHP_EOL; // 输出: the value of MY_CONSTANT
echo self::$myconstant; // 输出: The Paamayim Nekudotayim or double-colon.
}
}

$my_class = new Godwin();
print
$my_class::$myconstant;
$my_class::SaySomething();
echo
Godwin::$myconstant;
Godwin::SaySomething();

?>

print $my_class::$myconstant;
-2
michael at digitalgnosis dot removethis dot com
19 年前
如果你试图编写这样的类

<?php

class Base
{
static function
Foo ()
{
self::Bar();
}
}

class
Derived extends Base
{
function
Bar ()
{
echo
"Derived::Bar()";
}
}

Derived::Foo(); // 我们希望这能打印 "Derived::Bar()"

?>

那么你会发现 PHP 做不到(除非有人知道正确的方法?),因为 'self::' 指的是拥有代码的类,而不是在运行时被调用的实际类。(__CLASS__ 也不起作用,因为:A. 它不能出现在 :: 之前,B. 它像 'self' 一样工作)

但是如果你必须这样做,这里有一个(只有一点点讨厌的)解决方法

<?php

class Base
{
function
Foo ( $class = __CLASS__ )
{
call_user_func(array($class,'Bar'));
}
}

class
Derived extends Base
{
function
Foo ( $class = __CLASS__ )
{
parent::Foo($class);
}

function
Bar ()
{
echo
"Derived::Bar()";
}
}

Derived::Foo(); // 这次它起作用了。

?>

请注意,Base::Foo() 可能不再被声明为 'static',因为静态方法不能被覆盖(这意味着如果错误级别包含 E_STRICT,它将触发错误)。

如果 Foo() 接受参数,那么在 $class=__CLASS__ 之前列出它们,并且在大多数情况下,你可以在你的代码中忘记这个参数。

主要的注意事项是,当然,你必须在每个子类中覆盖 Foo(),并且在调用 parent::Foo() 时必须始终包含 $class 参数。
-3
valentin at balt dot name
14 年前
如何实现基于静态属性的单一存储位置。

<?php
class a {

public function
get () {
echo
$this->connect();
}
}
class
b extends a {
private static
$a;

public function
connect() {
return
self::$a = 'b';
}
}
class
c extends a {
private static
$a;

public function
connect() {
return
self::$a = 'c';
}
}
$b = new b ();
$c = new c ();

$b->get();
$c->get();
?>
-4
vvikramraj at yahoo dot com
15 年前
在尝试实现单例类时,你可能还想:
a) 通过将其设为私有来禁用 __clone
b) 通过定义 __clone 来抛出异常,来教训尝试克隆的用户。
-5
Mathijs Vos
15 年前
<?php
class foo
{
public static
$myStaticClass;

public function
__construct()
{
self::myStaticClass = new bar();
}
}

class
bar
{
public function
__construct(){}
}
?>

请注意,这行不通。
使用 self::$myStaticClass = new bar(); 而不是 self::myStaticClass = new bar();(注意 $ 符号)。
我花了整整一个小时才搞清楚。
-4
fakhar_anwar123 at hotmail dot com
4 年前
选择为正确答案的答案解决了问题。有一个有效的用例(设计模式),其中具有静态成员函数的类需要调用非静态成员函数,并且在此之前,这些静态成员也应该使用构造函数来实例化单例。

**案例:**
例如,我正在实现 Swoole HTTP 请求事件,为其提供一个回调作为具有静态成员的类。静态成员执行两件事;它通过在类构造函数中进行初始化来创建类的单例对象,第二件事是静态成员调用非静态方法 'run()' 来处理请求(通过与 Phalcon 桥接)。因此,没有构造函数的静态类和非静态调用对我来说不起作用。
To Top