0%

今天稍微深入一点点,学习一下几个重要的概念。

一、命名空间

命名空间这个概念是从PHP5.3之后开始引入的,当然PHP7也支持,命名空间主要解决以下两个问题

  • 你敲的代码和PHP内部或者是第三方类/函数/常量之间的命名冲突
  • 给很长的标识符名称创建一个别名(主要还是为了上一个问题)

命名空间的规则

  • 命名空间必须是程序脚本的第一条语句
  • 只有类(包括抽象类和traits)、接口、函数和常量受命名空间的影响
1
2
3
4
5
6
7
<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

子命名空间

1
2
3
4
5
6
7
<?php
namespace MyProject\Sub\Level;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

命名空间的使用

在文件系统中:

  • 相对文件名形式如foo.txt。它会被解析为 currentdirectory/foo.txt,其中 currentdirectory 表示当前目录。因此如果当前目录是 /home/foo,则该文件名被解析为/home/foo/foo.txt。
  • 相对路径名形式如subdirectory/foo.txt。它会被解析为 currentdirectory/subdirectory/foo.txt。
  • 绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt。

那么在命名空间中的元素:
有以下两个文件
1.php

1
2
3
4
5
6
7
8
9
10
<?php
namespace Foo\Bar\subnamespace;

const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>

2.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
namespace Foo\Bar;
include '1.php';

const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}

/* 非限定名称 */
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
?>

常量”NAMESPACE“的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。

在命名空间中访问全局类

1
2
3
4
5
6
7
8
9
<?php
namespace A\B\C;
class Exception extends \Exception {}

$a = new Exception('hi'); // $a 是类 A\B\C\Exception 的一个对象
$b = new \Exception('hi'); // $b 是类 Exception 的一个对象

$c = new ArrayObject; // 致命错误, 找不到 A\B\C\ArrayObject 类
?>

一、几个Array排序函数

  1. sort()和rsort()
    对数组中的元素按字母进行升序/降序排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    $b = array(“a”=>5,”b”=>2,”c”=>3);
    sort($b);
    print_r($b);
    /*Array
    (
    [0] => 2
    [1] => 3
    [2] => 5
    )*/
    rsort($b);
    print_r($b);
    /*Array
    (
    [0] => 5
    [1] => 3
    [2] => 2
    )*/
    ?>
  2. ksort()和krsort()
    对数组按照键名进行升序/降序排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    $b = array(“a”=>5,”b”=>2,”c”=>3);
    ksort($b);
    print_r($b);
    /*Array
    (
    [a] => 5
    [b] => 2
    [c] => 3
    )*/
    krsort($b);
    print_r($b);
    /*Array
    (
    [c] => 3
    [b] => 2
    [a] => 5
    )*/
    ?>
  3. asort()和arsort()
    对关联数组按照键值进行升序/降序排序,同时会保持索引关系
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    $b = array(“a”=>5,”b”=>2,”c”=>3);
    asort($b);
    print_r($b);
    /*Array
    (
    [b] => 2
    [c] => 3
    [a] => 5
    )*/
    ksort($b);
    print_r($b);
    /*Array
    (
    [a] => 5
    [b] => 2
    [c] => 3
    )*/
    ?>

二、require()和include

  1. require()一般放在程序最前面,执行前会将对应文件读取进来,require没有返回值
  2. include()一般不强制放在程序最前面,也可以放在程序中间,做流程控制,只有当执行到这里的时候才会把对应的文件读取进来,include有返回值
  3. require一个文件存在错误的话,程序就会中断执行,并抛出致命错误,include一个文件存在错误的话,程序不会中断,但是会显示一个警告
  4. require()通常来导入静态的内容,而include()则适合用导入动态的程序代码。
  5. require_once()会先检查目标文件的内容是不是在之前就已经导入过了,如果是的话,便不会再次重复导入同样的内容。

三、extends()和implements()

  1. extends,一般是单继承某个类,继承之后可以使用父类的方法,也可以重写父类的方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?php
    abstract class Father{
    public function getName(){
    return "I'm your Father";
    }
    }


    class Son extends Father{
    public function getFatherName(){
    echo $this->getName();
    }
    }

    $a = new Son();
    $a->getFatherName(); //I'm your Father
    ?>
  2. implements,一般是实现多个接口,接口的方法一般是空的,需要重写才能实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <?php
    interface iTemplate
    {
    public function setVariable($name, $var);
    public function getHtml($template);
    }

    class Template implements iTemplate
    {
    private $vars = array();

    public function setVariable($name, $var)
    {
    // TODO: Implement setVariable() method.
    $this->vars[$name] = $var;
    }

    public function getHtml($template)
    {
    // TODO: Implement getHtml() method.
    foreach ($this->vars as $name => $value){
    $template = str_replace(‘{‘ . $name . ‘}’, $value, $template);
    }

    return $template;
    }
    }
    ?>
  3. 在interface之间也可以声明为extends(多继承)的关系。注意一个interface可以extends多个其他interface。
1
2
3
4
5
<?php
class Template extends TemService implements iTem1, iTem2 {
//Code Here
}
?>
  1. 更多接口对象参考:PHP: 对象接口 - Manual

接下来研究:

  1. 命名空间
  2. 排序算法
  3. 设计模式

一、几个输出语句的区别

  1. echo
    echo没有返回值,只接受一个参数,可以不使用括号
    1
    2
    3
    4
    5
    6
    7
    <?php
    $a = echo("Hello World"); // 错误,因为 echo 没返回值,不能用来赋值
    echo "Hello World"; // 正确,输出 Hello World
    echo ("Hello World"); //正确,输出 Hello World
    echo ("Hello","Wrold"); //错误,因为传递多个参数的时候不能用括号
    echo "Hello"," World"," is", " web"; // 正确,不用括号的时候可以用逗号隔开多个值
    ?>
  2. print
    和echo几乎一样,但是print有返回值1,虽然没啥用,但是因此会比echo效率低一点
    1
    2
    3
    4
    5
    <?php
    $x = print("Hello World"); // 输出 Hello World
    echo $x; // 输出 1
    print "Hello World"; //输出 Hello World
    ?>
  3. printf
    printf主要用来格式化字符串
    1
    2
    3
    4
    <?php
    printf("First %s %s。","hello", "world"); // First hello world
    printf("This is %1\$s %1\$s","A", "B"); //输出 This is A A,因为只显示第一个参数两次,而没有用到第二个参数
    ?>
  4. sprintf
    和printf一样,但是没有输出,而只是格式化字符串
    1
    2
    3
    4
    <?php
    printf(“First %s %s。”,”hello”, “world”); // First hello world
    printf(“This is %1\$s %1\$s”,”A”, “B”); //输出 This is A A,因为只显示第一个参数两次,而没有用到第二个参数
    ?>
  5. print_r
    主要用来将数组、对象等数据类型以更易展示的形式输出来
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    $a = array ('a' => 'A', 'b' => 'B', 'c' => array ('a','b','c'));
    print_r ($a);
    ?>
    结果如下:
    Array
    (

    [a] => A
    [b] => B

    [c] => Array
    (

    [0] => a
    [1] => b
    [2] => c
    )
    )
  6. var_dump
    用于调试,还会把变量的内容和类型输出来,还有长度也会输出来
    1
    2
    3
    4
    5
    6
    <?php 
    $a=1.5;
    var_dump($a); //float(1.5)
    $a=2;
    var_dump($a); //int(2)
    ?>

二、单引号和双引号的区别

  1. 单引号只支持 \’和\转义,而双引号支持更多的转义
  2. 单引号不会解析变量值,双引号会
    1
    2
    3
    4
    5
    6
    7
    <?php
    $age = 20;
    $str1 = 'I am $age years old';

    $str2 = "I am $age years old";

    echo $str1,'<br />'; //输出: I am $age years old;
    echo $str2,'<br />'; // 输出:I am 20 years old;
    ?>
  3. 单引号比双引号快

    三、“::”、”->”和”=>”的区别

  4. “::”运算符是调用一个类中的静态成员的方法
    1
    2
    3
    4
    class test{
    protected static $instance;
    self::$instance = “abc”;
    }
  5. ”->”是操作类中成员变量或者方法的方法
    1
    2
    3
    4
    class test{
    private $test;
    $this->test = “abc”;
    }
  6. “=>”是映射数组中key和value时候使用的

四、构造函数和析构函数

  1. __construct 实例化对象的时候会被调用
  2. __destruct 对象呗销毁的时候被调用,因为PHP只会释放对象所占用的内存和相关资源,而由程序员自己申请的资源需要自己释放
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Test{
    protected $file = NULL;
    function __construct(){
    $this->file = fopen(“test.txt”,”r”);
    }
    function __destruct(){
    fclose($this->file);
    }
    }

五、__call()和__callStatic()

  1. __call(),当调用一个不可访问的方法时会调用这个方法。
  2. __callStatic(),当调用的静态方法不存在或者权限不足的时候,会调用这个方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Test 
    {
    public function __call ($name, $arguments) {
    echo “调用对象方法 ‘$name’ “. implode(‘, ‘,$arguments). “\n”;
    }
    public static function __callStatic ($name, $arguments) {
    echo “调用静态方法 ‘$name’ “. implode(‘, ‘, $arguments). “\n”; }
    }
    $obj = new Test;
    $obj->method1(‘参数 1’); //调用对象方法 'method1' 参数 1
    Test::method2(‘参数 2’); //调用静态方法 'method2' 参数 2

六、值传递和引用传递

  1. 值传递,在方法调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个存储单元,所以实参和形参有相同的值,却有着不同的存储单元
  2. 引用传递,传递的是对象的引用,形参和实参指向的是同一块地址

七、public、private和protected的区别

  1. public表示全局可以访问,比如类内部、外部和子类
  2. protected表示受保护的,只有本类和子类可以访问
  3. private表示私有的,只有本类内部可以访问

八、继承

  1. 通过用一个extends来继承基类的方法和成员。
  2. 子类只能继承父类的非私有(包括public和protected)成员变量和方法
  3. 当子类中定义的成员变量和父类中定义的成员变量同名时,子类中的成员变量会覆盖 父类的成员变量
  4. 当子类中的方法与父类中的方法有相同的方法签名(相同的方法名,相同的参数个数 与类型)时,子类将会覆盖父类的方法,而不是重载。

接下来准备研究

  1. 各种排序方法的内部实现,sort(),ksort(),asort(),arsort(),rsort()
  2. extends 和 implements 的区别
  3. require 和 require_once 还有 include