php编程 之 php基础三

时间:2023-12-16 20:52:32

1,php里的while循环

循环执行代码块指定的次数,或者当指定的条件为真时循环执行代码块。

while实例:

<html>
<body> <?php
$i=1;
while($i<=5) //注意,此处不支持简写。
{
echo "The number is " . $i . "<br>";
$i++;
}
?> </body>
</html>

do ...while...实例:

do
{
要执行的代码;
}
while (条件);

2,for循环

语法:

for (初始值; 条件; 增量)
{
要执行的代码;
}

只循环数字:

<?php
for ($i=1; $i<=5; $i++)
{
echo "The number is " . $i . "<br>";
}
?>

循环数组:

<?php
$x=array("one","two","three");
foreach ($x as $value) //键值对的键是$x,值是$value
{
echo $value . "<br>";
}
?>

3,函数

PHP 的真正威力源自于它的函数。在 PHP 中,提供了超过 1000 个内建的函数。

php内建函数手册:http://www.runoob.com/php/php-ref-array.html

创建:

<?php
function functionName() //名字最好具有提示性,函数名不能以数字开头
{
// 要执行的代码
}
?>

带参数:

<?php
function writeName($fname)
{
echo $fname . “how are u?”;
} writeName("Kai Jim"); //返回Kai Jim how are u?
?>

带返回值的函数:

<?php
function add($x,$y)
{
$total=$x+$y;
return $total; //return
} echo "1 + 16 = " . add(1,16);
?>

4 魔术常量

PHP 向它运行的任何脚本提供了大量的预定义常量。不大好解释,但是它们的数据类型是常量,但是具体值要看情况而定。

__LINE__:当前行的行号

<?php
echo '这是第 " ' . __LINE__ . ' " 行'; //返回2
?>

__FILE__:文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。

<?php
echo '该文件位于 " ' . __FILE__ . ' " ';
?>

__DIR__:文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。等于dirname(__FILE__)

<?php
echo '该文件位于 " ' . __DIR__ . ' " '; //返回"E:\wamp\www\test"
?>

__FUNCTION__:本常量返回该函数被定义时的名字(区分大小写)

<?php
function test() {
echo '函数名为:' . __FUNCTION__ ;
}
test();
?> //返回test

__CLASS__:返回该类再被定义时候的名字

<?php
class test {
function _print() {
echo '类名为:' . __CLASS__ . "<br>"; //返回test
echo '函数名为:' . __FUNCTION__ ; //返回_print
}
}
$t = new test();
$t->_print();
?>

__NAMESPACE__

当前命名空间的名称(区分大小写)。

<?php
namespace MyProject; echo '命名空间为:"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>

__METHOD__:类的方法名,返回该方法被定义时候的名字。

<?php
function test() {
echo '函数名为:' . __METHOD__ ;
}
test();
?>

__TRAIT__:Trait是为类似PHP的单继承语言而准备的一种代码复用机制。

php从以前到现在一直都是单继承的语言,无法同时从两个基类中继承属性和方法,为了解决这个问题,php出了Trait这个特性

用法:通过在类中使用use 关键字,声明要组合的Trait名称,具体的Trait的声明使用Trait关键词,Trait不能实例化

<?php
trait Dog{ //定义一个trait类,方法和class差不多,但是它不能被实例化
public $name="dog"; //公有属性是name
public function bark(){ //公有方法
echo "This is dog";
}
}
class Animal{
public function eat(){
echo "This is animal eat";
}
}
class Cat extends Animal{ //class 子类 extends 父类
use Dog; //trait类继承的写法,这样Cat类也会继承Dog类
public function drive(){
echo "This is cat drive";
}
}
$cat = new Cat(); //实例化cat
$cat->drive(); //返回this is cat drive
echo "<br/>";
$cat->eat(); //返回this is animal eat
echo "<br/>";
$cat->bark(); //返回this is dog
?>

由于trait和class的多继承有可能会造成父类子类属性和方法的冲突,所以我们再来个例子看一下覆盖问题:

<?php
class Base { //基类,拥有sayHello方法
public function sayHello() {
echo 'Hello ';
}
} trait SayWorld { //trait类,也拥有sayhello方法
public function sayHello() {
parent::sayHello(); //parent:: 的意思是调用父类但是不仅限于父类的方法,也就是会继承上一个sayHello的方法,也就是print hello
echo 'World!';
}
} class MyHelloWorld extends Base {
use SayWorld; //继承的是trait SayWorld
} $o = new MyHelloWorld();
$o->sayHello(); //返回hello world !
?>

5 命名空间:

https://blog.csdn.net/ss22_xiha/article/details/52694279这个教程还不错

感觉有点想python中的全局变量和局部变量。只不过明确地写出来了而已。

PHP 命名空间可以解决以下两类问题:

  1. 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
  2. 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

如何定义命名空间:

命名空间通过关键字namespace 来声明。如果你想使用命名空间,它必须在其它所有代码之前声明命名空间。语法格式如下;

<?php    
//一个文件中拥有多个命名空间
//不加大括号也行,不过加上比较严谨
declare(encoding='UTF-8');

//在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。即使是<html>也不行。好霸道啊,不过对这一点还是感觉不是特别理解
namespace MyProject {
//一堆代码
} namespace AnotherProject {
//一堆代码
}
?>
<?php
//全局代码和命名空间的代码写在一块
namespace MyProject { //这个是命名空间
//一堆代码
} namespace { // 这个是全局代码,注意全局代码的写法,namespace关键字后面不加任何东西,然后大括号括起来
//一堆代码
}
?>

 子命名空间:

与目录和文件的关系很像,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义。

<?php
namespace MyProject\Sub\Level; //声明分层次的单个命名空间,是反斜杠哦:\ //一堆代码 ?>

如何使用命名空间:

PHP 命名空间中的元素使用同样的原理。例如,类名可以通过三种方式引用:
  1. 非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。详情参见 使用命名空间:后备全局函数名称/常量名称
  2. 限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo
  3. 完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或\currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo

基本意思就是,如果你没指定命名空间那就默认为当前的命名空间,全局的也是这样的。为了防止和别的名称空间里的变量重名,你也可以指定命名空间的“相对路径”或者“绝对路径”

/* 非限定名称 */
foo(); // 解析为函数 Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo ,方法为 staticmethod,双冒号表示调用某类下的方法
echo FOO; // 解析为常量 Foo\Bar\FOO /* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
// 以及类的方法 staticmethod
echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO /* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
命名空间的导入
允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类 unix 文件系统中可以创建对其它的文件或目录的符号连接。
所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名
__NAMESPACE__
常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
<?php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>

关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。

不是很懂,留后

使用名称空间:

PHP 命名空间支持 有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名。

在PHP中,别名是通过操作符 use 来实现的. 下面是一个使用所有可能的三种导入方式的例子:

//使用use关键字导入,并且为这个名称空间取个别名:
<?php
namespace foo;
use My\Full\Classname as Another; //我要用xxx命名空间,别名是another // 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname; // 导入一个全局类
use \ArrayObject; $obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
?> //一行多个use语句并列
<?php
use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
?> //用另一个动态名称代替:
<?php
use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a; // 实际化一个 Another 对象
?>

使用命名空间的注意事项:

在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称;

对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量;

全局空间:

如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,我们在名称前加上前缀 \ 表示该名称是全局空间中的名称

<?php
namespace A\B\C;
$f = \fopen(...); // 调用全局的fopen函数
return $f;
?>

命名空间的顺序:

//不说了,直接上实例
<?php
namespace A;
use B\D, C\E as F; // 函数调用 foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()
// 再尝试调用全局函数 "foo" \foo(); // 调用全局空间函数 "foo" my\foo(); // 调用定义在命名空间"A\my"中函数 "foo" F(); // 首先尝试调用定义在命名空间"A"中的函数 "F"
// 再尝试调用全局函数 "F" // 类引用 new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象
// 如果未找到,则尝试自动装载类 "A\B" new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
// 如果未找到,则尝试自动装载类 "B\D" new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
// 如果未找到,则尝试自动装载类 "C\E" new \B(); // 创建定义在全局空间中的类 "B" 的一个对象
// 如果未发现,则尝试自动装载类 "B" new \D(); // 创建定义在全局空间中的类 "D" 的一个对象
// 如果未发现,则尝试自动装载类 "D" new \F(); // 创建定义在全局空间中的类 "F" 的一个对象
// 如果未发现,则尝试自动装载类 "F" // 调用另一个命名空间中的静态方法或命名空间函数 B\foo(); // 调用命名空间 "A\B" 中函数 "foo" B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果未找到类 "A\B" ,则尝试自动装载类 "A\B" D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
// 如果类 "B\D" 未找到,则尝试自动装载类 "B\D" \B\foo(); // 调用命名空间 "B" 中的函数 "foo" \B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法
// 如果类 "B" 未找到,则尝试自动装载类 "B" // 当前命名空间中的静态方法或函数 A\B::foo(); // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B" \A\B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>

6,面向对象

面向对象内容

  •  − 定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。

  • 对象 − 是类的实例。

  • 成员变量 − 定义在类内部的变量。该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可称为对象的属性。

  • 成员函数 − 定义在类的内部,可用于访问对象的数据。

  • 继承 − 继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。

  • 父类 − 一个类被其他类继承,可将该类称为父类,或基类,或超类。

  • 子类 − 一个类继承其他类称为子类,也可称为派生类。

  • 多态 − 多态性是指相同的函数或方法可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。

  • 重载 − 简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。

  • 抽象性 − 抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质,而忽略其他一些无关内容。任何类的划分都是主观的,但必须与具体的应用有关。

  • 封装 − 封装是指将现实世界中存在的某个客体的属性与行为绑定在一起,并放置在一个逻辑单元内。

  • 构造函数 − 主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

  • 析构函数 − 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做"清理善后" 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

定义类的语法:

<?php
class phpClass {
var $var1; //类的变量使用 var 来声明, 变量也可以初始化值。
var $var2 = "constant string"; function myfunc ($arg1, $arg2) { //函数定义类似 PHP 函数的定义,但函数只能通过该类及其实例化的对象访问。 [..]
}
[..]
}
?>

实例:

<?php
class Site {
/* 成员变量 */
var $url;
var $title; /* 成员函数 */
function setUrl($par){
$this->url = $par;
} function getUrl(){
echo $this->url . PHP_EOL; //PHP_EOL表示换行
} function setTitle($par){
$this->title = $par;
} function getTitle(){
echo $this->title . PHP_EOL;
}
}
?>

php使用new来创建实例:

如何调用呢?记住php类中调用实例的属性或者方法的时候,用“->”

$google = new Site; 

// 调用成员函数,设置标题和URL
$google->setTitle( "Google 搜索" ); $google->setUrl( 'www.google.com' ); // 调用成员函数,获取标题和URL
$google->getTitle(); $google->getUrl()

php构造函数:(这个比较重要了)

<?php
class Site {
/* 成员变量 */
var $url;
var $title; function __construct( $par1, $par2 ) { //这个是构造函数,感觉还是和js不一样,php是在class里面用构造函数,纯粹为了初始化的时候格式比较省事把,个人觉得,总觉得php的类是pytho向js的过度形式
$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', '菜鸟教程'); // 调用成员函数,获取标题和URL
$runoob->getTitle(); ?>

析构函数

析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。

<?php
class MyDestructableClass {
function __construct() {
print "构造函数\n";
$this->name = "MyDestructableClass";
} function __destruct() {
print "销毁 " . $this->name . "\n"; //这个是析构函数,很想python中的魔法方法,__del__这种的
}
} $obj = new MyDestructableClass();
?>

继承

class Child extends Parent {    //class子类extends父类
//代码
}

如果父类的属性和方法不能满足子类的需求,那子类可以选择重写这个方法。

访问控制

PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。

  • public(公有):公有的类成员可以在任何地方被访问。var定义的类属性会被当成公有
  • protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
  • private(私有):私有的类成员则只能被其定义所在的类访问。

实例,我们来具体看一下访问是如何被控制的:

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; // 这行会产生一个致命错误,说明实例不能访问类的protected属性
echo $obj->private; // 这行也会产生一个致命错误,说明实例不能访问类的private属性
$obj->printHello(); // 输出 Public、Protected 和 Private,说明类的方法本身可以访问自己的各种属性

接上一个程序

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,说明private属性不但不能被实例访问,还不能被继承
echo $obj2->protected; // 这行会产生一个致命错误,虽然产生了错误,但是并不能说明没有继承或者重写,实际上它就是已经被继承了而且被重写了,只是不能被实例访问而已
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined

备注方法的访问控制和属性的访问控制是基本一样的,

实例都不可以访问受保护的或者私有的方法,私有方法不可以被子类继承。

接口:

使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。

接口中定义的所有方法都必须是公有,这是接口的特性。

要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

<?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;
}
}

按照我的理解,接口更像是一个硬性规定,规定你类里必须有接口规定的内容,少一个不行,至于你某个接口内容的算法,你随意,我不care。

常量:

可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号。

常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。

class MyClass
{
const constant = '常量值'; //这样写 function showConstant() {
echo self::constant . PHP_EOL;
}
}

抽象类:

和接口有点像,

任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。

定义为抽象的类不能被实例化。

被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松,更加宽松也可以)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。

子类方法可以包含父类抽象方法中不存在的可选参数。

<?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;
?>
//返回
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

Static 关键字

声明类属性或方法为 static(静态),就可以不实例化类而直接访问。

静态属性不能被实例访问,但是静态方法可以。

由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。

静态属性不可以由对象通过 -> 操作符来访问。

<?php
class Foo {
public static $my_static = 'foo'; public function staticValue() {
return self::$my_static;
}
} print Foo::$my_static . PHP_EOL; //返回foo不用实例化可以直接访问
$foo = new Foo(); print $foo->staticValue() . PHP_EOL; //返回foo,因为实例化以后不可以访问static的属性
?>

final关键字 


PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。

<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called" . PHP_EOL;
} final public function moreTesting() { //final在public前
echo "BaseClass::moreTesting() called" . PHP_EOL;
}
} class ChildClass extends BaseClass {
public function moreTesting() { //子类无法覆盖该方法,继承还是可以的
echo "ChildClass::moreTesting() called" . PHP_EOL;
}
}
// 报错信息 Fatal error: Cannot override final method BaseClass::moreTesting()
?>

调用父类构造方法:

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 类中构造方法 // 调用 BaseClass、SubClass 构造方法
$obj = new SubClass();
//返回BaseClass 类中构造方法
//返回SubClass 类中构造方法 // 调用 BaseClass 构造方法
$obj = new OtherSubClass();
//返回BaseClass 类中构造方法