PHP命名空间及自动加载浅析

命名空间

什么是命名空间呢?

命名空间(英语:Namespace)表示标识符(identifier)的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

简单说来命名空间是为了解决不同库在同一个环境下使用时出现的命名冲突。例如我自己有一个函数名叫A,但是系统已经有一个A函数了,那就会出现冲突。

命名空间主要是为了解决代码中类和函数可能存在冲突的问题,而这个特性其他语言一早就有,PHP则是姗姗来迟,它的出现催生了
PSR-4 的诞生,从而也催生了 Composer 的兴起,所以是非常重要的特性。

类与对象


PHP中的命名空间

PHP从5.3版本开始引入了命名空间,之后许多现有PHP类库以及框架都开始支持它。那么PHP的命名空间怎么用呢?

命名空间的定义

命名空间是一个容器,这个容器主要是为了识别其下的类和函数。一旦定义了命名空间,它下面的代码就属于这个命名空间了,所以命名空间的定义要在代码的最开始行。

对于同一个包来说,同一个命名空间或者子命名空间的代码没有必要在一个 PHP
文件中定义,子命名空间下的代码是为了完成特定模块的工作,组合起来就是一个包完整的命名空间。

假如编写的代码没有定义命名空间,那说明它属于全局的命名空间(
符号),所以能够直接引用类或者函数(不用添加 符号)。

基本概念

每个类的定义都是关键class开头。

<?php
namespace NS
{
    class A
    {
        // 成员属性
        public $temp = '成员属性';

        // 方法
        public function displayVar()
        {
            // 使用伪变量$this调用成员属性
            echo $this->temp . "<br>";
        }
    }
// 使用new关键字实例化一个类
    $temp = new A();
    echo $temp->displayVar();

    class B extends A
    {
        // 构造方法
        function __construct()
        {
            $this->temp = '成员属性B继承于A';
        }
    }
    $temp = new B();
    echo $temp->displayVar();

    echo A::class;
}
?>

定义命名空间

下面是一个定义命名空间的例子

<?php    
//file a.php
namespace A;

const test = 'Atest'; 

function test() { 
    return __FUNCTION__; 
}

class Test{
    public function __construct(){
        return __METHOD__;
    }
}
?>

上面例子中就是一个典型的命名空间定义方法,只有constfunction,class受命名空间的约束。

引用命名空间标识符的三种方式

(1)Fully-qualified name

类似于操作系统上的绝对路径,而且是完整的路径,所以在理解的时候不会有误解。
比如在 new ABC ,那么 C 就被会解析到 AB 命名空间下的 C 类。

澳门新浦京电子游戏,(2)Qualified name

类似于操作系统上的相对路径,它包含部分名字并被引用到当前的命名空间。
比如 BC() 在命名空间 A 下调用,则最终引用的命名空间就是 ABC()。

(3)Unqualified name

类似于Qualified name,但是没包括子命名空间。
比如 C() 在命名空间 AB 下调用,则最终引用的命名空间就是 ABC()。

通过一个例子来说明三种引用方式:

namespace Example;
require_once "fnction.php";
class ClassA {}
function Function() {}

//完全限定名称
ExampleFunction();
ExampleBFunction(); 

//限定名称
BFunction(); //指向 ExampleBFunction();

//非限定名称
$test = new ClassA(); //resolves to ExampleClassA
Function(); //指向 ExampleFunction

注意:

  • Inside a namespace,假如在 current scope
    没有发现函数和常量的定义,PHP 不会报错。而是去全局命名空间中寻找。
  • Inside a namespace,假如在 current scope 没有发现类的定义,则 PHP
    会直接报错,不会去全局域中找对应的类,所以假如你需要引用一个
    internal 或用户自定义的类,必须使用完全限定名称。

先举个简单的例子,首先编写一段代码(定义在命名空间下),命名为
function.php :

namespace FooBarsubnamespace;
const FOO = 1;
function foo() 
{
    return "foorn";
}
class foo 
{
    static function staticmethod()
    {
        return __METHOD__ . "rn" ;
    }

    function foofunction()
    {
        return __METHOD__ . "rn" ;
    }
}

再编写一段代码 test.php,也是处于命名空间之下的代码:

namespace secondsp;
include 'function.php';

class foo
{
    function foofunction()
    {
        return __METHOD__ . "rn" ;
    }
}

function is_file($file)
{
    return true ;
}

//非限定名称:实例化secondspfoo类对象
$obj = new foo;  
echo $obj->foofunction();

//实例化FooBarsubnamespacefoo 类对象
$obj = new FooBarsubnamespacefoo ;
echo $obj->foofunction();

//代码会报错,在命名空间内部,假如无法找到当前命名空间下的类,则会报错
//$obj = new ArrayObject(array(1)); 
$obj = new ArrayObject(array(1)); 

//在命名空间内部,假如无法找到当前命名空间下的函数或者常量,则会寻找 native function
echo  strlen("nihao");

 //引用当前命名空间下的函数
var_dump(is_file('nihao')); //True
//引用全局函数
var_dump(is_file('nihao')); //False

访问控制

public(公有),protected(受保护)或 private(私有)。

使用命名空间

使用命名空间的方式如下:

<?php 
namespace B;
use A;

const test = 'Btest';
function test() { 
    return __FUNCTION__; 
}

class Test{
    public function __construct(){
        return __METHOD__;
    }
}

include "a.php";//必须包含A命名空间的文件

// 完全限定
// `Btest`从绝对位置查找输出,如果是全局函数则`test`
echo Btest;   //输出Btest

// 限定名称  
// 这里已经通过`use A`申明了在这个文件可以通过`A...`使用A命名空间的函数
echo Atest;    //输出Atest

// 非限定名称
// 非限定名称的函数`test`会从当前命名控件查找,即B
echo test;      //输出Btest

// namespace关键字代表当前命名空间
echo namespace/test;
?>

首先要注意的是命名空间只起申明作用,也就是在使用了命名空间的时候依然得把这个命名空间申明的那个文件包含进来。在使用中可以通过__NAMESPACE__来查看当前命名空间。

更多内容可以查看PHP官方文档

导入,别名

假如要使用的命名空间层级很长且数量很多,那么在使用的时候特别麻烦,所以可以使用
use
关键字导入命名空间、类、常量、函数等,然后可以使用它们直接引用完整的名称。而
alias 关键字可以给导入的类和函数等重命名。

举个例子如何使用 use 关键字,该代码处于全局命名空间之下:

include 'function.php';

use FooBarsubnamespacefoo ;
$obj = new foo;
echo $obj->foofunction();

use FooBarsubnamespacefoo  as aliasfunname;
$obj = new aliasfunname;
echo $obj->foofunction();

use FooBarsubnamespace ; 
$obj = new subnamespacefoo ;
echo $obj->foofunction();

use FooBarsubnamespace  as aliasname;
$obj = new aliasnamefoo ;
echo $obj->foofunction();

//由于调用代码并不在命名空间内,所以对于全局的类,无需引入使用
$obj = new ArrayObject(array(1)); 

//导入一个函数
use function FooBarsubnamespacefoo   ;
echo foo();

use function FooBarsubnamespacefoo  as func;
echo func();

use const  FooBarsubnamespaceFOO;
//echo FOO;

总结:

  • 和 Python 不一样,PHP
    中的命名空间是语义上的一种概念,和具体代码的位置、布局没有关系,换句话说,使用命名空间的代码需要自己引入库文件(所有文件),至于库文件如何组织无所谓;而在
    Python 中,假如模块或包中有一个 __init__.py 文件,则 Python
    解析器会自动引入包或所有模块的文件。
  • PHP
    中作用域的概念很弱化,全局域和局部域分的很清楚,比如在函数或类中无法引用全局空间中的变量。而在命名空间则不同,定义命名空间的代码,假如找不到对应命名空间下的常量和函数,则会使用全局的常量和函数;而假如找不到对应名命名空间下的类(包括自定义类),则代码直接报错。
  • 通过 use 关键字使用命名空间的,无须通过完全限定名称的方式(
    符号)导入,因为 PHP 已经假设导入的是完全限定的命名空间。
  • 通过 use 关键字可以导入常量、函数、类、接口、其他命名空间。
  • 命名空间是一种语言特性,为了追求更有效的使用,应该有一种使用规范和自动加载机制,这就是
    PSR-4 规范。

成员变量使用

可以用 ->(对象运算符):$this->property(其中 property
是该属性名)这种方式来访问非静态属性。 静态属性则是用
::(双冒号):self::$property 来访问。

自动加载

每个文件既要申明命名控件又要手动include是非常不智能的事情,所以在自己的PHP系统或者框架中可以使用自动加载技术,让系统自己去找

最简单的方式是利用函数__autoload函数,但是这个函数只能在非命名控件下定义,也就是全局情况下:

function __autoload($class) {
  $dir = './';
  set_include_path(get_include_path().PATH_SEPARATOR.$ids_dir);
  $class = str_replace('\', '/', $class) . '.php'; 
  require_once($class); }

如果在已经有了命名空间的类中,可以使用函数spl_autoload_register来注册一个类中的方法来代替__autoload

类常量

<?php
class MyClass
{
    const constant = 'constant value';

    function showConstant() {
        echo  self::constant . "n";
    }
}

echo MyClass::constant . "n";

$classname = "MyClass";
echo $classname::constant . "n"; // 自 5.3.0 起

$class = new MyClass();
$class->showConstant();

echo $class::constant."n"; // 自 PHP 5.3.0 起
?>

类的自动加载

spl_autoload_register()
函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。

本例尝试分别从 MyClass1.php 和 MyClass2.php 文件中加载 MyClass1 和
MyClass2 类。

<?php
spl_autoload_register(function ($class_name) {
    require_once $class_name . '.php';
});

$obj  = new MyClass1();
$obj2 = new MyClass2();
?>

构造函数

<?php
class BaseClass {
   function __construct() {
       print "In BaseClass constructorn";
   }
}

class SubClass extends BaseClass {
   function __construct() {
       parent::__construct();
       print "In SubClass constructorn";
   }
}

class OtherSubClass extends BaseClass {
    // inherits BaseClass's constructor
}

// In BaseClass constructor
$obj = new BaseClass();

// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();

// In BaseClass constructor
$obj = new OtherSubClass();
?>

析构函数

<?php
class MyDestructableClass {
   function __construct() {
       print "In constructorn";
       $this->name = "MyDestructableClass";
   }

   function __destruct() {
       print "Destroying " . $this->name . "n";
   }
}

$obj = new MyDestructableClass();
?>

Static(静态)关键字

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

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

用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。

抽象类

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

<?php
abstract class AbstractClass
{
 // 强制要求子类定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . "n";
    }
}

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_') ."n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."n";
?>

对象接口

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

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

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

实现(implements)

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

Trait代码复用

<?php

class A
{
    public function sayHello()
    {
        echo "Hello ";
    }
}

trait mytrait
{
    public function traitFunction()
    {
        parent::sayHello();
        echo "world!";
    }

}

class B extends A
{
    use mytrait;
}

$temp = new B();
$temp->traitFunction();

匿名类

PHP 7 开始支持匿名类。

<?php

// PHP 7 之前的代码
class Logger
{
    public function log($msg)
    {
        echo $msg;
    }
}

$util->setLogger(new Logger());

// 使用了 PHP 7+ 后的代码
$util->setLogger(new class {
    public function log($msg)
    {
        echo $msg;
    }
});

魔术方法

public void __set ( string $name , mixed $value )

public mixed __get ( string $name )

public bool __isset ( string $name )

public void __unset ( string $name )

在给不可访问属性赋值时,__set() 会被调用。

读取不可访问属性的值时,__get() 会被调用。

当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。

当对不可访问属性调用 unset() 时,__unset() 会被调用。

参数 $name 是指要操作的变量名称。__set() 方法的 $value 参数指定了
$name 变量的值。

属性重载只能在对象中进行。在静态方法中,这些魔术方法将不会被调用。
所以这些方法都不能被 声明为 static。从 PHP 5.3.0 起,
将这些魔术方法定义为 static 会产生一个警告。

遍历对象

PHP 5 提供了一种定义对象的方法使其可以通过单元列表来遍历, 例如用
foreach 语句。默认情况下,所有可见属性都将被用于遍历。

<?php

class MyClass
{
    public $var1 = 'value 1';
    public $var2 = 'value 2';
    public $var3 = 'value 3';

    protected $protected = 'protected var';
    private $private = 'private var';

    function iterateVisible()
    {
        echo "MyClass::iterateVisible:<br>";
        foreach ($this as $key => $value)
        {
            print '$key=>' . $key . "<br>";
            print '$value=>' . $value . "<br>";
        }
    }
}

$class = new MyClass();
$class->iterateVisible();

foreach ($class as $key => $value)
{
    print '$key=>' . $key . "<br>";
    print '$value=>' . $value . "<br>";
}

Final 关键字

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

<?php

class BaseClass
{
    public function display()
    {
        echo 'final';
    }

    final public function test()
    {
        echo 'Hello World!';
    }
}

class A extends BaseClass
{
    public function display()
    {
        echo 'A';
    }

    public function test()
    {
        echo 'haha';
    }
}

$temp = new A();
$temp->test();
#会报错,final方法不能重写

对象复制

在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果你有一个
GTK 窗口对象,该对象持有窗口相关的资源。

你可能会想复制一个新的窗口,保持所有属性与原来的窗口相同,但必须是一个新的对象(因为如果不是新的对象,那么一个窗口中的改变就会影响到另一个窗口)。

还有一种情况:

如果对象 A 中保存着对象 B 的引用,当你复制对象 A
时,你想其中使用的对象不再是对象 B 而是 B 的一个副本,那么你必须得到对象
A 的一个副本。

对象比较

当使用比较运算符(==)比较两个对象变量时,比较的原则是:

如果两个对象的属性和属性值
都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等。

而如果使用全等运算符(===),这两个对象变量一定要指向某个类的同一个实例(即同一个对象)。

类型约束

PHP 5 可以使用类型约束。

如果一个类或接口指定了类型约束,则其所有的子类或实现也都如此。

类型约束不能用于标量类型如 int 或 string。Traits 也不允许。

<?php

class MyClass
{
    public function test_class(OtherClass $otherclass)
    {
        echo $otherclass->var;
        echo "<br>";
    }

    public function test_array(array $input_array)
    {
        print_r($input_array);
    }
}

class OtherClass
{
    public $var = 'Hello World!';
}

$myclass    = new MyClass();
$otherclass = new OtherClass();
$myclass->test_class($otherclass);

$input_array = ['one' => 'first', 'two' => 'second'];
$myclass->test_array($input_array);

后期静态绑定

自 PHP 5.3.0 起,PHP
增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。

self:: 的限制

使用 self::
或者 CLASS 对当前类的静态引用,取决于定义当前方法所在的类:

后期静态绑定的用法

<?php

class A
{
    public static function who()
    {
        echo __CLASS__;
    }
    public static function test()
    {
//        self::who(); // 输出A
        static::who(); // 输出B
    }
}

class B extends A
{
    public static function who()
    {
        echo __CLASS__;
    }
}

$temp = new B();
$temp::test();

对象和引用

在php5
的对象编程经常提到的一个关键点是“默认情况下对象是通过引用传递的”。

但其实这不是完全正确的。下面通过一些例子来说明。

PHP 的引用是别名,就是两个不同的变量名字指向相同的内容。 在 PHP
5,一个对象变量已经不再保存整个对象的值。只是保存一个标识符来访问真正的对象内容。
当对象作为参数传递,作为结果返回,或者赋值给另外一个变量,另外一个变量跟原来的不是引用的关系,
只是他们都保存着同一个标识符的拷贝,这个标识符指向同一个对象的真正内容。

<?php

class A
{
    public $foo = 1;

}

$a = new A();
$b = $a;

$b->foo = 2;
echo $a->foo . "n"; // 输出为2

对象序列化

序列化对象 – 在会话中存放对象

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。
unserialize()函数能够重新把字符串变回php原来的值。
序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

<?php
//
//include("class.inc");
//
//$a = new A();
//$a->show_one();
//
//$s = serialize($a);
//file_put_contents('store', $s);

// 反序列化必须要包含此文件。
include("class.inc");
$s = file_get_contents('store');
$a = unserialize($s);

$a->show_one();

命名空间

  1. 解决PHP内部的类、函数、常量或第三方类、函数、常量之间的名字冲突。
  2. 为很长的标识名称创建一个别名,提高源代码的可读性。

<?php

namespace myname;

class MyClass{}

function myfunction(){}

const MYCONST = 1;

$a = new MyClass();
$c = new mynameMyClass;
$a = strlen('hi');
$d = namespaceMYCONST;
$d = __NAMESPACE__ . 'MYCONST';
echo $d;
echo constant($d);

定义命名空间

虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:

类、接口、函数和常量。

命名空间通过关键字namespace来声明。如果一个文件中包含命名空间,它必须在其它代码之前声明命名空间,
有一个除外:declare关键字。

<?php

namespace spaceMyProject;

const CONNECT_OK = 1;

class Connection{}
function connect(){}

echo __NAMESPACE__;

在同一个文件中定义多个命名空间

在同一个文件中定义多个命名空间有两种语法形式。

不建议使用这种语法在单个文件中定义多个命名空间,区间会显得不明确。

<?php

namespace MyProject;

const CONNECT_OK = 1;
class Connection
{
}

function connect()
{
}

echo __NAMESPACE__ . "<br>";

namespace AnotherProject;

const CONNECT_OK = 1;
class Connection
{
}

function connect()
{
}

echo __NAMESPACE__ . "<br>";
// 不建议使用这种语法在单个文件中定义多个命名空间,区间会显得不明确。

使用大括号来定义多个命名空间

<?php

namespace MyProject
{
    const CONNECT_OK = 1;
    class Connection
    {
    }

    function connect()
    {
    }

    echo __NAMESPACE__ . "<br>";
}

namespace AnotherProject
{
    const CONNECT_OK = 1;
    class Connection
    {
    }

    function connect()
    {
    }

    echo __NAMESPACE__ . "<br>";

}

使用命名空间:别名、导入

允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。

<?php

namespace MyProject
{
    const CONNECT_OK = 1;
    class Connection
    {
        public function __construct()
        {
            echo "MyProject __construct" . "<br>";
        }
    }

    function connect()
    {
        echo "MyProject connect" . "<br>";
    }

    echo __NAMESPACE__ . "<br>";
}

namespace AnotherProject
{
    const CONNECT_OK = 1;
    class Connection
    {
        public function __construct()
        {
            echo "AnotherProject __construct" . "<br>";
        }
    }

    function connect()
    {
        echo "AnotherProject connect" . "<br>";
    }

    $temp = new MyProjectConnection();
    use MyProject as A;
    $temp = new AConnection();
    use MyprojectConnection as AConnection;
    $temp = new AConnection();

    echo __NAMESPACE__ . "<br>";
}

全局空间

如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与PHP引入命名空间概念前一样。

在名称前加上前缀””表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。

<?php

namespace wwwweb;

class MyClass
{
    public function display()
    {
        try
        {
            echo 'Hello World!';
        }
        catch (Exception $e)
        {
            echo 'try...catch';
        }
    }
}

$temp = new MyClass();
$temp->display();

使用命名空间:后备全局函数/常量

在一个命名空间中,当PHP遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。

类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称。

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

<?php

namespace ABC;

class Exception extends Exception
{
}

$a = new Exception('message');
$b = new Exception('message');

echo strlen('Hello World!'); // 正常输出12
$c = new ArrayObject(); // 致命错误,找不到ABCArrayObject类

命名空间名称解析规则

命名空间名称定义

  • 非限定名称Unqualified name

名称中不包含命名空间分隔符的标识符,例如Foo

  • 限定名称Qualified name

名称中含有命名空间分隔符的标识符,例如FooBar

  • 完全限定名称Fully qualified name

名称中包含命名空间分隔符,并以命名空间分隔符开始的标识符,例如FooBar。

生成器

生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现Iterator接口的方式,性能开销和复杂性大大降低。

生成器允许你在foreach代码块中写代码来迭代一组数据而不需要在内存中创建一个数组,在内存中创建一个大数组可能会使你的内存达
到上限,或者会占据可观的处理时间。

生成器函数,就像一个普通的自定义函数一样,和普通函数只返回一次不同的是,生成器可以根据需要yield多次,以便生成需要迭代的值。

一个简单的例子就是使用生成器来重新实现 range() 函数。 标准的 range()
函数需要在内存中生成一个数组包含每一个在它范围内的值, 然后返回该数组,
结果就是会产生多个很大的数组。 比如,调用 range(0, 1000000)
将导致内存占用超过 100 MB。

<?php

function xrange($start, $end, $step = 1)
{
    for ($i = $start; $i <= $end; $i += $step)
    {
        yield $i;
    }
}
// 直接报500错误
foreach (range(0, 1000000) as $val)
{
    echo $val;
}
// 进入大循环
foreach (xrange(0, 1000000) as $val)
{
    echo $val;
}

生成器语法

我的理解就是链表来的,一个指针像游标一样,循环迭代。

一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值。

当一个生成器被调用的时候,它返回一个可以被遍历的对象。当你遍历这个对象的时候PHP将会在每次需要值的时候调用生成器函数,
并在产生一个值之后保存生成器的状态,这样它就可以在需要产生下一个值的时候恢复调用状态。

yield关键字

生成器函数的核心就是yield关键字。它最简单的调用形式看起来像一个return申明,不同之处在于普通return会返回值并
终止函数的执行,而yield会返回一个值给循环调用此生成器的代码并且只是暂停执行生成器函数。

<?php

function test()
{
    for ($i = 0; $i <= 10; $i++)
    {
        // 注意:变量$i的值在不同的yield之间是保持传递的。
        yield $i;
    }
}

$temp = test();
foreach ($temp as $value)
{
    echo "$value" . "<br>";
}

指定键名来生成值

<?php

$input = <<<'EOF'
1;PHP;Likes dollar signs
2;Python;Likes whitespace
3;Ruby;Likes blocks
EOF;

function input_parse($input)
{
    foreach (explode("n", $input) as $line)
    {
        $fields = explode(';', $line);
        $id     = array_shift($fields); // array_shift将数组开头的单元移出数组

        yield $id => $fields;
    }
}

foreach (input_parse($input) as $key => $value)
{
    echo '$key=>' . $key . "<br>";
    echo '$value=>' . print_r($value) . "<br>";
}

生成null值

yield可以在没有参数传入的情况下被调用来生成一个NULL值并配对一个自动的键名。

可以使用生成器来初始化一个null数组。

<?php

function test()
{
    foreach (range(1, 3) as $i)
    {
        yield;
    }
}
var_dump(iterator_to_array(test()));

使用引用来生成值

生成函数可以像使用值一样来使用引用生成。

<?php

function &test()
{
    $value = 10;

    while ($value > 0)
    {
        yield $value;
    }
}

foreach (test() as &$value)
{
    echo (--$value) . '...';
}

PHP中的引用

在PHP中引用意味着用不同的名字访问同一个变量内容。这并不像C的指针:
例如你不能对他们做指针运算,他们并不是实际的内存地址。

在PHP中,变量名和变量的内容是不一样的,因此同样的内容可以有不同的名字。

$a = 'Hello world!';
$b = &$a;
$b = 'new Hello world!';
//echo $a;

function test(&$temp){
    $temp = 'function Hello world!';
}
test($b);
echo $a;

引用返回

引用返回用在当想用函数找到引用应该被绑定在哪一个变量上面时。

不要用返回引用来增加性能,引擎足够聪明来自己进行优化。

仅在有合理的技术原因时才返回引用!要返回引用,请看如下示例:

class temp
{
    public $value = 100;

    public function &getValue()
    {
        return $this->value;
    }
}

$obj   = new temp();
$value = &$obj->getValue();
echo $value . '<br>'; // 输出100
$obj->value = 9;
echo $value . '<br>'; // 输出9

取水引用

当unset一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了。

$a = 1;
$b = &$a;
unset($a);

引用定位

许多PHP的语法结构
是通过引用机制实现的,所以上述有关引用绑定的一切也都适用于这些结构。

global引用

当用global $var声明一个变量时实际上建立了一个到全局变量的引用。

global $var;
$var = & $GLOBALS['var']; // 与上一行代码是等价的。

$this

在一个对象的方法中,$this永远是调用它的对象的引用。

php如何使用类

class myclass{
    //成员变量(公有访问控制)
    public $myvar;
    //构造函数
    function __construct($myvar){
        $this->myvar = $myvar;
    }
    //封装
    function setValue($myvar){
        $this->myvar = $myvar;
    }
    function getValue(){
        return $this->myvar;
    }
    //析构函数
    function __destruct(){
        unset($this->myvar);
    }
}
//类继承
class myextends extends myclass{
}
$myclass = new myextends("Moments");
echo $myclass->getValue();
  • 如何使用静态变量

class myclass{
    //使用静态变量
    public static $myvar = "Moments";
    public function myfun(){
        return self::$myvar;
    }
}
$myclass = new myclass();
echo myclass::$myvar;
echo $myclass->myfun();        
  • 如何使用抽象类

abstract class myclass{
    public $myvar;
    //强制要求子类定义之些方法
    abstract protected function setValue($myvar);
    //普通方法
    public function getValue(){
        return $this->myvar;
    }
}
class myextends extends myclass{
    function setValue($myvar){
        $this->myvar = $myvar;
    }
    function getValue(){
        return parent::getValue();
    }
}
$myclass = new myextends();
$myclass->setValue("Moments");
echo $myclass->getValue();      
  • 如何使用对象接口

#接口中定义的所有方法都必须是公有
interface myinterface{
    //接口不支持成员变量,可以使用常量
    const myconst = "myconst";
    //类中必须实现接口中定义的所有方法。
    public function setValue($myvar);
    public function getValue();
}
class myextends implements myinterface{
    public function setValue($myvar){
        $this->myvar = $myvar;
    }
    public function getValue(){
        return $this->myvar;
    }
}
$myclass = new myextends();
$myclass->setValue("Moments");
echo $myclass->getValue();
echo myinterface::myconst;

 

衿华客

php 教程

  1. PHP简介
  2. PHP安装
  3. PHP语法
  4. PHP数据类型
  5. PHP变量
  6. PHP运算符
  7. PHP流程控制
  8. PHP函数
  9. PHP类与对象
  10. PHP字符串
  11. PHP正则表达示
  12. PHP文件
  13. PHP图形图像
  14. PHPXML
  15. PHP会话缓存
  16. PHP异常处理
  17. PHP数据库
  18. PHP日期时间戳
  19. PHP代码风格规范

server 环境

  1. ubuntu入门
  2. docker入门
  3. git入门
  4. iterm入门

frame 框架

  1. laravel入门
  2. dingo入门
  3. JWT入门
  4. Laravel框架关键技术解析
  5. laravel则修笔记
  6. rpc入门
  7. rabbitmq入门
  8. opencc多国语言
  9. laravel兄弟连笔记
  10. laravel进阶

case 实例

  1. php面试题笔记
  2. python图标提取
  3. 字幕乱码问题
  4. 支付宝接口调用
  5. laravel开发笔记

db 数据库

  1. elasticsearch入门
  2. 数据库操作
  3. 数据库设计
  4. redis入门

help

  • 帮助文档
  • 流程图帮助文档

发表评论

电子邮件地址不会被公开。 必填项已用*标注