[PHP] 02 - Namespace & Class
两个比较大的话题,独立成本篇。
面向对象编程
一、命名空间
PHP 命名空间可以解决以下两类问题:
- 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
- 为很长的标识符名称 (通常是为了缓解第一类问题而定义的) 创建一个别名(或简短)的名称,提高源代码的可读性。
- 模块化写法
[1] 可以在同一个文件中定义不同的命名空间代码,如:
<?php namespace MyProject; const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } namespace AnotherProject; const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } ?>
[2] 其实,加个大括号会更好些。
<?php namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace AnotherProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } ?>
- 全局代码
<?php namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace { // 全局代码 session_start(); $a = MyProject\connect(); echo MyProject\Connection::start(); } ?>
- declare 语句
<?php declare(encoding='UTF-8'); // 定义多个命名空间和不包含在命名空间中的代码
namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace { // 全局代码 session_start(); $a = MyProject\connect(); echo MyProject\Connection::start(); } ?>
- 子命名空间
<?php namespace MyProject\Sub\Level; // 声明分层次的单个命名空间 const CONNECT_OK = 1; class Connection { /* ... */ } function Connect() { /* ... */ } ?>
上面的例子创建了:
- 常量 MyProject\Sub\Level\CONNECT_OK
- 类 MyProject\Sub\Level\Connection
- 函数 MyProject\Sub\Level\Connect
二、命名空间使用
/* implement */
三、面向对象
列举概念:类,对象,成员变量,成员函数,继承,父类,子类,多态,重载,抽象性,封装,构造函数,析构函数。
[1] 一个综合性的例子:
<?php class Site {
/* 成员变量 */ var $url; var $title;
---------------------------------------------------------
function __construct( $par1, $par2 ) { $this->url = $par1; $this->title = $par2; }
---------------------------------------------------------
/* 成员函数 */ function setUrl($par){ $this->url = $par; } function getUrl(){ echo $this->url . PHP_EOL; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title . PHP_EOL; } }
---------------------------------------------------------
$runoob = new Site('www.runoob.com', '菜鸟教程'); $taobao = new Site('www.taobao.com', '淘宝'); $google = new Site('www.google.com', 'Google 搜索');
---------------------------------------------------------
// 调用成员函数,获取标题和URL $runoob->getTitle(); $taobao->getTitle(); $google->getTitle(); $runoob->getUrl(); $taobao->getUrl(); $google->getUrl(); ?>
[2] 析构函数
<?php class MyDestructableClass { function__construct() { print "构造函数\n"; $this->name = "MyDestructableClass"; } function__destruct() { print "销毁 " . $this->name . "\n"; } } $obj = new MyDestructableClass(); ?>
php中对应的malloc是什么? - ref: php 内存分配
php内核中的内存分配 使用的函数有 emalloc(), erealloc() ,这两个函数分别是malloc(),realloc()函数的封装
[3] extends 继承
<?php // 子类扩展站点类别 class Child_Site extends Site { var $category; function setCate($par){ $this->category = $par; } function getCate(){ echo $this->category . PHP_EOL; } }
[4] override 重写
[5] 访问控制
- 【属性】的访问控制
<?php /** * Define MyClass */ class MyClass { public $public = 'Public'; protected $protected = 'Protected'; private $private = 'Private'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } }
------------------------------------------------------------- $obj = new MyClass(); echo $obj->public; // 这行能被正常执行 echo $obj->protected; // <-- 这行会产生一个致命错误 echo $obj->private; // <-- 这行也会产生一个致命错误 $obj->printHello(); // 输出 Public、Protected 和 Private /** * Define MyClass2 */ class MyClass2 extends MyClass { // 可以对 public 和 protected 进行重定义,但 private 而不能 protected $protected = 'Protected2'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } }
-------------------------------------------------------------
$obj2 = new MyClass2(); echo $obj2->public; // 这行能被正常执行 echo $obj2->private; // <-- 未定义 private echo $obj2->protected; // <-- 这行会产生一个致命错误 $obj2->printHello(); // 输出 Public、Protected2 和 Undefined ?>
- 【方法】的访问控制
<?php /** * Define MyClass */ class MyClass { public function __construct() { }
---------------------------------------------------------------
public function MyPublic() { } protected function MyProtected() { } private function MyPrivate() { } // 此方法为公有 function Foo() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); } }
---------------------------------------------------------------
$myclass = new MyClass; $myclass->MyPublic(); // 这行能被正常执行 $myclass->MyProtected(); // 这行会产生一个致命错误 $myclass->MyPrivate(); // 这行会产生一个致命错误 $myclass->Foo(); // 公有,受保护,私有都可以执行 /** * Define MyClass2 */ class MyClass2 extends MyClass { // 此方法默认为公有 function Foo2() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); // 这行会产生一个致命错误 } }
--------------------------------------------------------------- $myclass2 = new MyClass2; $myclass2->MyPublic(); // 这行能被正常执行 $myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行 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 ?>
[6] 接口的实现
<?php // 声明一个'iTemplate'接口 interface iTemplate { public function setVariable($name, $var); public function getHtml($template); } // 实现接口 class Template implements iTemplate { private $vars = array(); public function setVariable($name, $var) { $this->vars[$name] = $var; } public function getHtml($template) { foreach($this->vars as $name => $value) { $template = str_replace('{' . $name . '}', $value, $template); } return $template; } }
[7] 抽象类
<?php abstract class AbstractClass { // 强制要求子类定义这些方法 abstract protected function getValue(); abstract protected function prefixValue($prefix); // 普通方法(非抽象方法) public function printOut() { print $this->getValue() . PHP_EOL; } } class ConcreteClass1 extends AbstractClass { protected function getValue() { return "ConcreteClass1"; } public function prefixValue($prefix) { return "{$prefix}ConcreteClass1"; } } class ConcreteClass2 extends AbstractClass { public function getValue() { return "ConcreteClass2"; } public function prefixValue($prefix) { return "{$prefix}ConcreteClass2"; } } $class1 = new ConcreteClass1; $class1->printOut(); echo $class1->prefixValue('FOO_') . PHP_EOL; $class2 = new ConcreteClass2; $class2->printOut(); echo $class2->prefixValue('FOO_') . PHP_EOL; ?>
考点:
此外,子类方法可以包含父类抽象方法中不存在的可选参数。
例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则也是可以正常运行的。
[8] const 常量
类中的常量,自带static属性。
[9] Static 关键字
考点:
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
<?php class Foo { public static $my_static = 'foo'; public function staticValue() { return self::$my_static; } } print Foo::$my_static . PHP_EOL; $foo = new Foo(); print $foo->staticValue() . PHP_EOL; ?>
[10] Final 关键字
如果父类中的方法被声明为 final,则子类无法覆盖该方法。
如果一个类被声明为 final,则不能被继承。
[11] 调用父类构造方法
需要自己去手动调用。
<?php class BaseClass { function __construct() { print "BaseClass 类中构造方法" . PHP_EOL; } }
class SubClass extends BaseClass { function __construct() { parent::__construct(); // 子类构造方法不能自动调用父类的构造方法 print "SubClass 类中构造方法" . PHP_EOL; } }
class OtherSubClass extends BaseClass { // 继承 BaseClass 的构造方法 } // 调用 BaseClass 构造方法 $obj = new BaseClass(); // 调用 BaseClass、SubClass 构造方法 $obj = new SubClass(); // 调用 BaseClass 构造方法 $obj = new OtherSubClass(); ?>
考点
一、继承中的 Static关键字
Ref: PHP static关键字的用法及注意点
- static变量
a). 可以不赋初值
b). 不会存储引用。
- 延迟静态绑定
class A { public static function foo() { static::who(); // Jeff: 不再为定义当前方法所在的类,而是实际运行时所在的类的who() } public static function who() { echo __CLASS__."\n"; } } class B extends A { public static function test() { A::foo(); // 是在A的运行时环境中 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
同理,也是要注意”运行时“这个概念!
class A { protected static $var1 = null; protected static $var2 = null;
public static function test(){ if(!static::$var2){ static::$var2 = static::$var1; } echo get_called_class().' '.static::$var2.' '; } }
class B extends A { protected static $var1 = 'b'; }
class C extends A { protected static $var1 = 'c'; }
B::test(); // 第一次调用test, var2还未赋值. C::test(); // 第二次调用test, var2已赋值.