给自己看的
简介
PHP 对待对象的方式与引用 (references) 和句柄 (handles) 相同,即每个变量都持有对象的引用,而不是整个对象的拷贝。
用户空间命名指南
全局命名空间
以下代码结构会进入全局命名空间:
- functions(函数)
- classes(类)
- interfaces(接口)
- constants(常量,并非类常量)
- 在函数/方法之外定义的变量
规则
以下列表指出了 PHP 工程在选择新的内部标识符时保留给自己的权利。最终指南是官方的» 编码标准:
- PHP 拥有最顶层命名空间,但是会尝试找到合体的描述命名以避免任何明显的冲突。
- 函数名在两个词中间使用下划线,类名则同时使用 camelCase 和 PascalCase 规则。
- PHP 在任何扩展库的全局符号前附加上扩展库的名称(此规则在过去则有无数例外)。例如:
- curl_close()
- mysql_query()
- PREG_SPLIT_DELIM_CAPTURE
- new DOMDocument()
- strpos()(以前的一个失误例子)
- new SplFileObject()
- Iterators 和 Exceptions 则只是简单加上 "Iterator" 和 "Exception" 后缀。例如:
提示
防止命名冲突方法:
- 在命名后加上下划线,和三四个不常用的字符。(不再推荐)
- 命名空间。
- 减少全局作用域的变量的数量。
变量范围
- include 就是把代码物理的塞进来。
- 全局范围变量 global 和 $GLOBALS 。$GLOBALS 是一个超全局数组。
- static 。
static $int = 1+2; // Static declarations are resolved in compile-time.
变量
变量定义:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
。
基础
<?php
class SimpleClass{
public $var;
}
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
unset($instance); // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
/**********
Notice: Undefined variable: instance in C:\Users\haobi\Desktop\a.php on line 14
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
**********/
<?php
class SimpleClass{
public $var;
}
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
/**********
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
**********/
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
class Child extends Test
{}
$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);
$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);
$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
var_dump($obj4 instanceof Test);
var_dump($obj3 == $obj4);
var_dump($obj3 === $obj4);
/**********
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
**********/
ClassName::class
编译时候解析,并不会加载该类,如果不存在,并不会发生错误。
$this is a reference to the calling object (usually the object to which the method belongs, but possibly another object, if the method is called statically from the context of a secondary object).
属性
<?php
$ref = new StdClass();
$ref->{'ref-type'} = 'Journal Article';
var_dump($ref);
// 但是不能 $ref->ref-type ,神奇。
<?php
class Foo {
// As of PHP 7.1.0 开始支持设置可见性
public const AA = 'bar';
private const BB = 'baz';
protected const CC = 'baz';
}
echo Foo::AA, PHP_EOL;
echo Foo::BB, PHP_EOL; // wrong
echo Foo::CC, PHP_EOL; // wrong
自动加载 classes
Autoloading is not available if using PHP in CLI interactive mode.
<?php
spl_autoload_register(function ($name) {
echo "Want to load $name.\n";
throw new MissingException("Unable to load $name.");
});
try {
$obj = new NonLoadableClass();
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
/**
Want to load NonLoadableClass.
Want to load MissingException.
Fatal error: Class 'MissingException' not found in testMissingException.php on line 4
*/
构造与解析函数
The destructor will be called even if script execution is stopped using exit(). Calling exit() in a destructor will prevent the remaining shutdown routines from executing.
Note:
Destructors called during the script shutdown have HTTP headers already sent. The working directory in the script shutdown phase can be different with some SAPIs (e.g. Apache).
Note:
Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error.
可见性
<?php
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new Foo();
$myFoo->test();
/**
Bar::testPrivate
Foo::testPublic
*/
同一个类的不同对象可以相互访问它们的私有属性和保护属性。
接口
接口也可以继承,通过使用 extends 操作符。
请注意,可以在接口中声明构造函数,在某些情况下可能有用,例如 供工厂使用。
在接口中声明的所有方法都必须是公共的; 这是一个接口的本质。
接口常量的工作方式与类常量完全相同,除非它们不能被继承它们的类/接口覆盖。
Traits
<?php
trait PropertiesTrait {
public $same = true;
public $different = false;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true; // Allowed as of PHP 7.0.0; E_STRICT notice formerly
public $different = true; // Fatal error
}
# Example using parent class:
<?php
class TestClass {
public static $_bar;
}
class Foo1 extends TestClass { }
class Foo2 extends TestClass { }
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: World World
?>
# Example using trait:
<?php
trait TestTrait {
public static $_bar;
}
class Foo1 {
use TestTrait;
}
class Foo2 {
use TestTrait;
}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: Hello World
匿名类
<?php
function anonymous_class()
{
return new class {};
}
if (get_class(anonymous_class()) === get_class(anonymous_class())) {
echo 'same class';
} else {
echo 'different class';
}
// same class
魔术方法
<?php
class A
{
public $var1;
public $var2;
public static function __set_state($an_array) // As of PHP 5.1.0
{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
eval('$b = ' . var_export($a, true) . ';');
var_dump($b);
/**
object(A)#2 (2) {
["var1"]=>
int(5)
["var2"]=>
string(3) "foo"
}
*/
<?php
class C {
private $prop;
public function __construct($val) {
$this->prop = $val;
}
public function __debugInfo() {
return [
'propSquared' => $this->prop ** 2,
];
}
}
var_dump(new C(42));
?>
/**
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}
*/
This method is called by var_dump() when dumping an object to get the properties that should be shown. If the method isn't defined on an object, then all public, protected and private properties will be shown.
This feature was added in PHP 5.6.0.
后期静态绑定
static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
/**
A
C
C
*/
对象和引用
<?php
class A {
public $foo = 1;
}
$e = new A;
function foo($obj) {
// ($obj) = ($e) = <id>
$obj->foo = 4;
}
foo($e);
echo $e->foo."\n";
// 输出 4