Giter VIP home page Giter VIP logo

blogs's Introduction

@Holos 博客

所有博客文章均以 GitHub Issue 的形式发布,点此阅读

blogs's People

Contributors

smilefish1987 avatar

Stargazers

 avatar

Watchers

 avatar  avatar

blogs's Issues

在紫藤庐和星巴克 (Starbucks) 之间

转一篇龙应台老师写的文章
不论是北京还是吉隆坡,香港还是台北,都有一个“国际化”的共同面貌:星巴克 (Starbucks) 咖啡馆不管在哪一个城市里都可以俏生生地站在街角,7-11商店取代了原来老先生老太太开的杂货店,最流行的嘻哈音乐和服饰到处可见,好莱坞的电影比欧洲还早上市。生活的韵律也与国际同步:二月十四日买花过情人节,十月底戴上面具参加“万圣节”变装游行,十一月有人吃火鸡过感恩节,十二月广场上万人空巷载歌载舞庆祝耶诞节;年底,放烟火、开香槟,倒数时,亲吻你身边的人。

新加坡和香港已经是英语的城市,台北的新政府为了“国际化”开始要求政府公文要有英文版,公务员要考英文,全民学英语,而最后的目标则是:把英语变成正式的官方语言。

从北京到吉隆坡,“国际化”成为一个举国上下努力追求的目标。但是,慢一点,究竟什么叫“国际化”呢?

如果说,“现代化”指的是,在传统的文化土壤上引进新的耕法——**制度、科学精神、工业技术等等,从而发展出一种新的共处哲学与生活模式。如果说,“全球化”指的是,随着科技与经济的跨越国界,深层的文化体系,始料所未及地,也冲破了国家与民族的传统界线。原来沿着那条线而形成的千年传统——种种律法、信仰、道德、价值,面对“全球化”,不得不重新寻找定义。“现代化”是很多开发**家追求的目标;“全球化”是一个正在急速发生的现实,在这个现实中,已开发国家盘算如何利用自己的优势,开发**家在趁势而起的同时暗暗忧虑“自己不见了”的危险。

那么,“国际化”是什么呢?按照字义,就是使自己变得跟“国际”一样,可是,谁是“国际”呢?变得跟谁一样呢?把英语变成官方语言,是要把**变成英国美国,还是印度菲律宾?还是香港新加坡?当执政者宣布要将别国的语言拿来作自己的官方语言时,他对于自己国家的安身立命之所在、之所趋,有没有认真地思考过呢?

牧羊人穿过草原

一九七八年我第一次到欧洲;这是启蒙运动、工业革命的发源地,先进国家的聚集处,我带着满脑子对“现代化”的想像而去。离开机场,车子沿着德法边境行驶。一路上没看见预期中的高科技、超现实的都市景观,却看见他田野依依,江山如画。树林与麦田尽处,就是村落。村落的红瓦白墙起落有致,衬着教堂尖塔的沈静。斜阳钟声,鸡犬相闻。绵延数百里,竟然像中古世纪的图片。

车子在一条乡间小路停下。上百只毛茸茸圆滚滚的羊,像下课的孩子一样,推着挤着闹着过路,然后从草原那头,牧羊人出现了。他一脸胡子,披着蓑衣,手执长杖,在羊群的簇拥中缓缓走近。夕阳把羊毛染成淡淡粉色,空气流动着草汁的酸香。

我是震惊的;我以为会到处看见人的“现代”成就的骄傲展现,但是不断撞见的,却是贴近泥土的默不作声的“传统”。穿过浓绿的草原,这牧羊人缓缓向我走近,就像旧约圣经里的牧羊人走近一个口渴的旅人。

尔后在欧洲的长期定居,只是不断见证传统的生生不息。生老病死的人间礼仪——什么时辰唱什么歌、用什么颜色、送什么花,对什么人用什么遣词与用句,井井有条。春夏秋冬的生活韵律——暮冬的化妆游行以驱鬼,初春的彩绘鸡蛋以庆生,夏至的广场歌舞以休憩,耶诞的庄严静思以祈福。

千年礼乐,不绝如缕,并不曾因“现代化”而消失或走样。至于生活环境,不论是罗马、巴黎还是柏林,为了一堵旧时城墙、一座破败教堂、一条古朴老街,都可能花大成本,用高科技,不计得失地保存修复,为了保留传统的气质氛围。

欧洲的现代与传统之间也有一种紧张的拉锯,但是他们至少认识到,传统的“气质氛围”,并不是一种肤浅的怀旧情怀。当人的成就像氢气球一样向不可知的无限的高空飞展,传统就是绑着氢气球的那根粗绳,紧连着土地。它使你仍旧朴实地面对生老病死,它使你仍旧与春花秋月冬雪共同呼吸,使你的脚仍旧踩得到泥土,你的手摸得到树干,你的眼睛可以为一首古诗流泪,你的心灵可以和两千年前的作者对话。

传统不是怀旧的情绪,传统是生存的必要。

我发现,自己原来对“现代化”的预期是片面的。先进国家的“现代化”是手段,保护传统是目的。譬如在环境生态上所做的巨额投资与研发,其实不过是想重新得回最传统最单纯的“小桥流水人家”罢了。大资本、高科技、研究与发展,最终的目的不是飘向无限,而是回到根本——回到自己的语言、文化,自己的历史、信仰,自己的泥土。

语言不是木棍

于是我看见:越先进的国家,越有能力保护自己的传统;传统保护得越好,对自己越有信心。越落后的国家,传统的流失或支离破碎就越厉害,对自己的定位与前景越是手足无措,进退失据。

亚洲的人民过西洋情人节但不知道Valentine是什么;化妆游行又不清楚Carnival的意义何在;吃火鸡大餐不明白要对谁感恩;耶诞狂欢又没有任何宗教的反思。凡节庆都必定联系着宗教或文化历史的渊源;将别人的节庆拿来过,有如把人家的祖宗牌位接来祭拜,却不知为何祭拜、祭拜的是何人。节庆的热闹可以移植,节庆里头所蕴含的意义却是移植不来的。节庆变成空洞的消费,而自己传统中随着季节流转或感恩或驱鬼或内省或祈福的充满意义的节庆则又弃之不顾。

究竟要如何给生活赋予意义?说得出道理的人少,手足无措的人,多。

**的领导人要把英语变成官方语言,更是真正的不知所云。语言难道是一支死的木棍,伸手拿来就可以使?

语言不是木棍,语言是活生生的千年老树,盘根错节、深深扎根在文化和历史的土壤中。移植语言,就是移植文化和历史,移植价值和信念,两者不可分。殖民者为了更改被殖民者的价值观,**的第一步就是让被殖民者以殖民者的语言为语言。香港和新加坡就这样成为英语的社会。娴熟英语,通晓英语世界的价值观与运作模式,固然使新加坡和香港这样的地方容易与国际直接对话,但是他们可能也要付出代价,文化的代价。英语强势,可能削弱了本土语言文化—— 譬如汉语或马来语——的发展,而英语文化的厚度又不足以和纽约或伦敦相提并论,结果可能是两边落空,两种文化土壤都可能因为不够厚实而无法培养出参天大树。

本国没有英语人口,又不曾被英语强权殖民过的**,为什么宣称要将英语列为官方语言?把英语列为官方语言在文化上意味着什么后果?**的执政者显然未曾深思。进退失据,莫此为甚。

国际化,是知识

不是移植别人的节庆,不是移植别人的语言,那么“国际化”是什么?它是一种知己知彼。知己,所以要决定什么是自己安身立命、生死不渝的价值。知彼,所以有能力用别人听得懂的语言、看得懂的文字、讲得通的逻辑词汇,去呈现自己的语言、自己的观点、自己的典章礼乐。它不是把我变得跟别人一样,而是用别人能理解的方式告诉别人我的不一样。所以“国际化”是要找到那个“别人能理解的方式”,是手段,不是目的。

找到“别人能理解的方式”需要知识。不知道非洲国家的殖民历史,会以为自己的“悲哀”是世界上最大的悲哀。不清楚国际对**市场的反应,会永远以政治的单一角度去思考**问题。不了解美伊战争后的欧美角力,不了解联合国的妥协政治,不了解俄罗斯的转型,不了解回教世界的内在思维,不了解全球化给国家主权和民族文化带来的巨大挑战……不了解国际,又如何奢谈找到什么对话的语言让国际了解亚洲呢?

越是先进的国家,对于国际的知识就越多。知识的掌握,几乎等于国力的展示,因为知识,就是权力。知道越多,掌握越多。如果电视是一种文化指标,那么**目前二十四小时播报国内新闻,把自己放大到铺天盖地的肚脐眼自我沉溺现象,不只是国家落后的象征,已经是文化的变态。人们容许电视台彻底剥夺自己知的权利,保持自己对国际的淡漠无知,而同时又抱怨国际不了解自己的处境,哀叹自己是国际孤儿,不是很矛盾吗?

星巴克 (Starbucks) 还是紫藤庐

我喜欢在星巴克 (Starbucks) 买咖啡。不见得因为它的咖啡特别好,而是因为,你还没进去就熟悉它的一切了。你也许在耶路撒冷,也许在伦敦,在北京,或者香港,突然下起冷雨来,远远看见下一个街角闪着熟悉的灯,你就知道在那里可以点一大杯拿铁咖啡加一个牛角面包,虽然这是一个陌生的城市。

“全球化”,就是使你“客舍似家家似寄”。我更喜欢在台北的古迹紫藤庐喝茶,会朋友。茶香缭绕里,有人安静地回忆在这里聚集过的一代又一代风流人物以及风流人物所创造出来的历史,有人慷慨激昂地策划下一个社会改造运动;紫藤花闲闲地开着,它不急,它太清楚这个城市的身世。台北市有五十八家Starbucks,台北市只有一个紫藤庐。全世界有六千六百家Starbucks,全世界只有一个紫藤庐。“国际化”不是让Starbucks进来取代紫藤庐;“国际化”是把自己敞开,让Starbucks进来,进来之后,又知道如何使紫藤庐的光泽更温润优美,知道如何让别人认识紫藤庐——“我” ——的不一样。

星巴克 (Starbucks) 越多,每一个城市自己的紫藤庐越重要。

PHP 5.4 新增特性

PHP 5.4 新增特性

PHP 5.4 的新增特性可以参考 PHP手册,具体的特性列表如下:

  1. 新增支持 traits
    PHP 是单继承的语言。自 PHP 5.4.0 起,PHP 实现了代码复用的一个方法,称为 traits。
    Traits 是一种为类似 PHP 的单继承语言而准备的代码复用机制。Trait 为了减少单继承语言的限制,
    使开发人员能够自由地在不同层次结构内独立的类中复用方法集。Traits 和类组合的语义是定义了一
    种方式来减少复杂性,避免传统多继承和混入类(Mixin)相关的典型问题。
    Trait 和一个类相似,但仅仅旨在用细粒度和一致的方式来组合功能。Trait 不能通过它自身来实例化
    它为传统继承增加了水平特性的组合;也就是说,应用类的成员不需要继承
  2. 新增短数组语法
    例如: $a = [1,2,3] 或者 $b = ['a'=>1,'b'=>2]
  3. 新增支持对函数返回数组的成员访问解析
    可以通过表达式 foo()[0],访问foo()函数返回的数组的第一个元素
  4. 现在 闭包 支持 $this
  5. 现在不管是否设置 short_open_tag php.ini 选项,<?= 将总是可用
  6. 新增在实例化时访问类成员
    可以通过 (new Foo)->bar() 这样的表达式访问类成员
  7. 现在支持 Class::{expr}() 语法
  8. 新增二进制直接量
    可以通过0b开头定义二进制字面量,例如: $b = 0b001001101;
  9. 改进解析错误信息和不兼容参数的警告
  10. SESSION 扩展现在能追踪文件的 上传进度
  11. 内置用于开发的 CLI 模式的 web server
    可以通过php -S host:port的方式启动内置web server
namespace Name\TraitTest{
    trait AddAndSub{
        function add($a,$b){
            return $a+$b;
        }

        function sub($a,$b){
            return $a-$b;
        }

        function hello()
        {
            echo "trait hello()",PHP_EOL;
        }
    }

    class Base{
        function hello(){
            echo "Base hello()",PHP_EOL;
        }
    }

    class Test extends Base{
        use AddAndSub;
    }

    class Smile extends Base{
        use AddAndSub;
        function hello(){
            echo "Smile hello()",PHP_EOL;
        }
    }


    // PHP Fatal error:  Cannot instantiate trait Name\TraitTest\AddAndSub
    //$a = new AddAndSub();

    $test = new Test();
    echo  $test->add(1,2),PHP_EOL;
    echo  $test->sub(10,1),PHP_EOL;

    $smile = new Smile();
    echo $smile->add(999,123),PHP_EOL;
    echo $smile->sub(1000,23),PHP_EOL;

    /* 从基类继承的成员被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的
方法,而 trait 则覆盖了被继承的方法 */
    echo  $test->hello(),PHP_EOL; 
    echo $smile->hello(),PHP_EOL;


    //  多个 trait,通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中

    trait Hello{
        public function hello(){
            echo "Hello",PHP_EOL;
        }
    }

    trait World{
        public function world(){
            echo "World",PHP_EOL;
        }
    }

    class HelloWorld{
        use Hello,World;
    }

    $helloWorld = new HelloWorld();
    $helloWorld->hello();
    $helloWorld->world();

    /* 如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。
    为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用
     冲突方法中的哪一个。
    以上方式仅允许排除掉其它方法,as 操作符可以将其中一个冲突的方法以另一个名称来引入*/
    trait A{
        public function sayHello(){
            echo "A",PHP_EOL;
        }
    }

    trait B{
        public function sayHello(){
            echo "B",PHP_EOL;
        }
    }

    class TestInsteadof{
        use A,B{
            B::sayHello insteadof A;
        }
    }

    $ti = new TestInsteadof();
    $ti->sayHello();

    class TestAlians{
        use A,B{
            A::sayHello insteadof B;
            B::sayHello as hello;
        }
    }

    $ta = new TestAlians();
    $ta->sayHello();
    $ta->hello();

    //使用 as 语法还可以用来调整方法的访问控制

    trait T1{
        public function sayHello(){
            echo "Hello,world!";
        }
    }

    class Test1{
        use T1{ sayHello as protected;}
    }

    class Test2{
        use T1{ sayHello as private myPrivateHello;}
    }

    $test1 = new Test1();
    //$test1->sayHello(); // 错误

    $test2 = new Test2();
    $test2->sayHello();
    //$test2->myPrivateHello(); // 错误

    /* 从 trait 来组成 trait,在 trait 定义时通过使用一个或多个 trait,它能够组合其它 trait 中的
部分 或全部成员 */

    trait TraitHelloWorld{
        use Hello,World;
    }

    class Test3{
        use TraitHelloWorld;
    }

    $test3 = new Test3();
    $test3->hello();
    $test3->world();


    // Trait 的抽象成员,为了对使用的类施加强制要求,trait 支持抽象方法的使用

    trait TestAB{
        public function hello(){
            echo "hello",PHP_EOL;
        }

        abstract public function test();
    }

    class MyTestAB{
        use TestAB;

        public function test(){
            echo "just test",PHP_EOL;
        }
    }

    $myTestab = new MyTestAB();
    $myTestab->hello();
    $myTestab->test();

    //Trait 的静态成员,Trait中可以定义静态方法,方法中还能定义静态变量

    trait Counter{
        public function inc(){
            static $count = 0;
            $count++;
            echo $count,PHP_EOL;
        }

        public static function m(){
            echo "just test in m method",PHP_EOL;
        }
    }

    class C1{
        use Counter;
    }

    class C2{
        use Counter;
    }

    $c = new C1();
    $c->inc();
    C1::m();
    $c2 = new C2();
    $c2->inc();

    /*Trait中同样可以定义属性,如果 trait 定义了一个属性,那类将不能定义同样名称的属性,
     否则会产生一个错误。如果该属性在类中的定义与在 trait 中的定义兼容(同样的可见性和
     初始值) 则错误的级别是 E_STRICT,否则是一个致命错误 */

    trait PropertyTrait{
        public $data = 10;
        public static $m = 123;
    }

    class C3{
        use PropertyTrait;
    }

    $c3 = new C3();
    echo $c3->data,PHP_EOL;
    echo C3::$m,PHP_EOL;
}

PHP 5.2 及以前版本的关键特性

PHP 5.2 及以前版本的关键特性

PHP 5.2 的新增特性就是JSON 支持,包括 json_encode(), json_decode() 等函数,JSON 算是在 Web 领域非常常用的数据交换格式,可以被 JS 直接支持,JSON 实际上是 JS 语法的一部分。JSON 系列函数,可以将 PHP 中的数组结构与 JSON 字符串进行转换

$arr = ['name'=>'smilefish','data'=>['a','b','c']];

$json = json_encode($arr);

echo $json,PHP_EOL;

// json_decode 默认会返回一个对象
$object = json_decode($json);
print_r($object);

// json_decode 将第二个参数设置成true,返回一个数组
$arr = json_decode($json,1);
print_r($arr);

输出

{"name":"smilefish","data":["a","b","c"]}
stdClass Object
(
    [name] => smilefish
    [data] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )

)
Array
(
    [name] => smilefish
    [data] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )

)

PHP 5.2之前的重要特性有:
autoload
自动加载类 (autoload)可以参考 PHP 手册。在 PHP 5 中,可以定义一个 __autoload() 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。

function __autoload($className){
    echo "__autoload class:",$className,PHP_EOL;
    require_once("lib/".$className.".php");
}

new Test();

PHP 手册上说,spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载。因此,不再建议使用 __autoload() 函数,原因是一个项目中仅能有一个这样的 __autoload() 函数,因为 PHP 不允许函数重名。在以后的版本中它可能被弃用。spl_autoload_register — 注册给定的函数作为 __autoload 的实现。

将函数注册到SPL __autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。

如果在你的程序中已经实现了__autoload()函数,它必须显式注册到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()或spl_autoload_call()

如果需要多条 autoload 函数,spl_autoload_register() 满足了此类需求。 它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。相比之下, __autoload() 只可以定义一次

spl_autoload_extensions('.class.php');

//echo get_include_path().PATH_SEPARATOR."lib/";
set_include_path(get_include_path().PATH_SEPARATOR."lib/");

spl_autoload_register();

$test = new Test();


function classLoader($className){
    echo "__autoload class:",$className,PHP_EOL;
    require_once("lib/".$className.".php");
}

spl_autoload_register('classLoader');
new Test();


function classLoader($className){
    echo "__autoload class:",$className,PHP_EOL;
    //require_once("lib/".$className.".php");
    set_include_path("lib/");
    spl_autoload($className);
}

spl_autoload_register('classLoader');
new Test();

PDO
PDO(PHP DATA OBJECT)PHP 数据对象,请参考 PHP手册。它为PHP访问数据库定义了一个轻量级的一致接口。实现 PDO 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 PDO 扩展自身并不能实现任何数据库功能;必须使用一个 具体数据库的 PDO 驱动 来访问数据库服务。

按照传统的风格,访问 MySQL 数据库应该是这样子:

// 连接到服务器,选择数据库
$conn = mysql_connect("localhost", "user", "password");
mysql_select_db("database");

// 执行 SQL 查询
$type = $_POST['type'];
$sql = "SELECT * FROM `table` WHERE `type` = {$type}";
$result = mysql_query($sql);

// 打印结果
while($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
      foreach($row as $k => $v)
      print "{$k}: {$v}\n";
}

// 释放结果集,关闭连接
mysql_free_result($result);
mysql_close($conn);

为了能够让代码实现数据库无关,即一段代码同时适用于多种数据库(例如以上代码仅仅适用于MySQL),PHP 官方设计了 PDO。
除此之外,PDO 还提供了更多功能,比如:

面向对象风格的接口
SQL预编译(prepare), 占位符语法
更高的执行效率,作为官方推荐,有特别的性能优化
支持大部分SQL数据库,更换数据库无需改动代码
上面的代码用 PDO 实现将会是这样:

// 连接到数据库
$conn = new PDO("mysql:host=localhost;dbname=database", "user", "password");

// 预编译SQL, 绑定参数
$query = $conn->prepare("SELECT * FROM `table` WHERE `type` = :type");
$query->bindParam("type", $_POST['type']);

// 执行查询并打印结果
foreach($query->execute() as $row)
{
     foreach($row as $k => $v)
     print "{$k}: {$v}\n";
}

MySQLi
但如果你需要使用 MySQL 所特有的高级功能,那么你可能需要尝试一下 MySQLi, 因为 PDO 为了能够同时在多种数据库上使用,不会包含那些 MySQL 独有的功能。
MySQLi 是 MySQL 的增强接口,同时提供面向过程和面向对象接口,也是目前推荐的 MySQL 驱动,旧的C风格 MySQL 接口将会在今后被默认关闭。
MySQLi 的用法和以上两段代码相比,没有太多新概念,在此不再给出示例,可以参见 PHP 手册

类型约束
PHP 5 可以使用类型约束,请参考 PHP 手册。函数的参数可以指定必须为对象(在函数原型里面指定类的名字),接口,数组(PHP 5.1 起)或者 callable(PHP 5.4 起)。不过如果使用 NULL 作为参数的默认值,那么在调用函数的时候依然可以使用 NULL 作为实参。

a.如果一个类或接口指定了类型约束,则其所有的子类或实现也都如此。
b.类型约束不能用于标量类型如 int 或 string。Traits 也不允许
c.函数调用的参数与定义的参数类型不一致时,会抛出一个可捕获的致命错误。
d.类型约束不只是用在类的成员函数里,也能使用在函数里
e.类型约束允许 NULL 值

// 限制第一个参数为 MyClass, 第二个参数为可执行类型,第三个参数为数组
function func(MyClass $a, callable $b, array $c)
{
// ...
}

PHP 魔术方法

PHP 魔术方法

PHP语言中以__(双下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。魔术方法包括:__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 。开发者可以通过魔术方法,改变类的行为,进行类似其他语言的元编程。

class MagicMethod{
    private $data  = array();

    //当对不可访问属性调用unset()函数时,该函数会被调用
    public function __unset($name){
        echo "Unsetting ",$name,PHP_EOL;
        unset($this->data[$name]);
    }

    //当对不可访问属性调用isset()和empty()时,该函数会被调用
    public function __isset($name){
        echo "Is ",$name, " set ?",PHP_EOL;
        return isset($this->data[$name]);
    }

    //构造函数,创建对象前会调用,用于对象的初始化
    public function __construct(){
        echo "__construct",PHP_EOL;
    }

    //析构函数,对对象进行回收时前会调用该函数,用于资源的回收
    public function __destruct(){
        echo "__destruct",PHP_EOL;
    }


    //在给不可访问属性赋值时,该函数会被调用
    public function __set($name,$value){

        echo "Setting ",$name," to the value:",$value,PHP_EOL;
        $this->data[$name]  = $value;
    }

    /* 当serialize()函数被调用时,该方法会在序列化前被调用。可以用于清理对象,
    并返回一个包含对象中所有应该被序列化的变量名称的数组。如果该方法未返回任何内容,
    则NULL被序列化,并产生一个E_NOTICE级别的错误。该函数不能返回父类的私有成员的名称。
    这样会产生一个E_NOTICE级别的错误,可以使用Serializeable接口来替代 */ 
    public function __sleep(){
        echo "__sleep()",PHP_EOL;
        return $this->data;
    }

    //读取不可访问属性的值时,该方法会被调用
    public function __get($name){
        echo "Getting ",$name," value",PHP_EOL;
        if(array_key_exists($name,$this->data)){
            return $this->data[$name];
        }

        return null;
    }

    //当类定义了__call方法(),在对象中调用一个不可访问的方法时,该方法会被调用
    public function __call($name,$arguments){
        echo "calling method :",$name,PHP_EOL;
        echo "the arguments are:",print_r($arguments,true),PHP_EOL;
    }

    /* 当类定义了,静态的方法__callStatic(),以静态方式调用一个不可访问的方法时,
     该方法会被调用 */   
    public static function __callStatic($name,$arguments){

        echo "calling method :",$name,PHP_EOL;
        echo "the arguments are:",print_r($arguments,true),PHP_EOL;
    }

    /* unserialize()函数,会在反序列化之前,先调用该函数预先准备对象需要的资源。
      __wakeup()经常用在反序列化操作中,用于重新建立数据库连接,或者执行其他初始化操作 */
    public function __wakeup(){
        echo "__wakeup()",PHP_EOL;
    }

    /* 当类的对象被当作一个字符串使用时,该方法会被调用,此方法必须返回一个字符串,
     否则将发出一条E_RECOVERABLE_ERROR级别的致命错误,也不能在此方法中抛出异常,
     这么做会导致致命的错误 */
    public function __toString()
    {
        return "Hello,world!";
    }

    // 当尝试一调用函数的方式调用一个对象时,__invoke()方法会被自动调用
    public function __invoke($args){
        echo "__invoke()",PHP_EOL;
        var_dump($args);
    }

    /* 当调用var_export()导出类时,此静态方法会被调用,本方法的唯一参数是一个数组,
     其中包含按array('property'=>value,...)格式排列的类属性; */
    public static function __set_state($args){
        echo "__set_state()",PHP_EOL;
        $obj = new MagicMethod();
        $obj->data = $args;
        return $obj;
    }
    /* 当使用var_dump()函数输出对象的信息时,如果实现了该函数会使用该函数的返回值,
     如果没有实现该函数会输出对象所有的public,protected,private的成员属性 */
    public function __debugInfo(){
        return [
            'title'=> 'magicMethod',
            'data'=> print_r($this->data,true)
        ];
    }

    /* 对象复制可以通过clone关键字完成(如果可能,这将调用对象的__clone()方法),
      对象中的__clone()方法不能被直接调用。当对象被复制后PHP5会对对象的所有属性执行一个
     浅拷贝,所有的引用属性仍然会是一个指向原来变量的引用。当复制完成时,如果定义了__clone()
     方法,则新创建的对象(复制生成的对象)中的__clone()方法会被调用,可用于修改属性的
     值(如果有必要的话) */
    public function __clone(){
        echo "__clone()",PHP_EOL;
    }
}

// 测试代码

$magic = new MagicMethod();

$magic->hello(123);
MagicMethod::hello(123123123123123123123123123123123123);
echo "hello,world!",PHP_EOL;

echo $magic->b,PHP_EOL;
echo isset($magic->c),PHP_EOL;
echo empty($magic->d),PHP_EOL;
unset($magic->d);
$semagic = serialize($magic);
print_r(unserialize($semagic));
$magic->a = 123;

echo $magic,PHP_EOL;

$magic(6);

echo var_export($magic,true);

var_dump($magic);

$magic2 = clone $magic;

2016 阅读书单

#2016 阅读书单

阅读改变人生,下面是今年阅读读完的清单,将持续更新,希望完成今年的阅读任务:

1.《被劫持的私生活》 作者:肉唐僧 豆瓣阅读

2.《皮囊》 作者:蔡崇达 豆瓣阅读

3.《时间的朋友2015》作者:罗振宇 微信读书

准备阅读的书籍:

1.《圣杯与剑》

Elasticsearch集群健康状态的获取

1.查看elasticsearch集群监控状态
http://localhost:8204/_cluster/health?pretty

{
  "cluster_name" : "viva",
  "status" : "green",    //green表示健康  yellow表示亚健康  red表示不健康
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 3,
  "active_shards" : 3,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0
}

2.查看elasticsearch集群的状态
http://localhost:8204/_cluster/stats?pretty

{
  "timestamp" : 1450366439969,
  "cluster_name" : "viva",
  "status" : "green",
  "indices" : {
    "count" : 64,
    "shards" : {
      "total" : 447,
      "primaries" : 288,
      "replication" : 0.5520833333333334,
      "index" : {
        "shards" : {
          "min" : 3,
          "max" : 16,
          "avg" : 6.984375
        },
        "primaries" : {
          "min" : 3,
          "max" : 8,
          "avg" : 4.5
        },
        "replication" : {
          "min" : 0.0,
          "max" : 1.0,
          "avg" : 0.328125
        }
      }
    },
    "docs" : {
      "count" : 223298454,
      "deleted" : 10060337
    },
    "store" : {
      "size_in_bytes" : 162470487340,
      "throttle_time_in_millis" : 112550530
    },
    "fielddata" : {
      "memory_size_in_bytes" : 29842840,
      "evictions" : 0
    },
    "filter_cache" : {
      "memory_size_in_bytes" : 83533752,
      "evictions" : 0
    },
    "id_cache" : {
      "memory_size_in_bytes" : 0
    },
    "completion" : {
      "size_in_bytes" : 0
    },
    "segments" : {
      "count" : 1362,
      "memory_in_bytes" : 880810868,
      "index_writer_memory_in_bytes" : 683408,
      "index_writer_max_memory_in_bytes" : 2037731328,
      "version_map_memory_in_bytes" : 5976,
      "fixed_bit_set_memory_in_bytes" : 0
    },
    "percolate" : {
      "total" : 0,
      "time_in_millis" : 0,
      "current" : 0,
      "memory_size_in_bytes" : -1,
      "memory_size" : "-1b",
      "queries" : 0
    }
  },
  "nodes" : {
    "count" : {
      "total" : 3,
      "master_only" : 0,
      "data_only" : 0,
      "master_data" : 3,
      "client" : 0
    },
    "versions" : [ "1.7.1" ],
    "os" : {
      "available_processors" : 36,
      "mem" : {
        "total_in_bytes" : 202579611648
      },
      "cpu" : [ {
        "vendor" : "Intel",
        "model" : "Xeon",
        "mhz" : 2001,
        "total_cores" : 12,
        "total_sockets" : 12,
        "cores_per_socket" : 32,
        "cache_size_in_bytes" : 15360,
        "count" : 3
      } ]
    },
    "process" : {
      "cpu" : {
        "percent" : 567
      },
      "open_file_descriptors" : {
        "min" : 1303,
        "max" : 1362,
        "avg" : 1334
      }
    },
    "jvm" : {
      "max_uptime_in_millis" : 7447032417,
      "versions" : [ {
        "version" : "1.8.0_40",
        "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
        "vm_version" : "25.40-b25",
        "vm_vendor" : "Oracle Corporation",
        "count" : 3
      } ],
      "mem" : {
        "heap_used_in_bytes" : 23317137312,
        "heap_max_in_bytes" : 160739229696
      },
      "threads" : 460
    },
    "fs" : {
      "total_in_bytes" : 4204953993216,
      "free_in_bytes" : 3968499347456,
      "available_in_bytes" : 3968499347456,
      "disk_reads" : 248021,
      "disk_writes" : 186868283,
      "disk_io_op" : 187116304,
      "disk_read_size_in_bytes" : 2672438272,
      "disk_write_size_in_bytes" : 5486048710656,
      "disk_io_size_in_bytes" : 5488721148928,
      "disk_queue" : "0.7",
      "disk_service_time" : "0.8"
    },
    "plugins" : [ {
      "name" : "bigdesk",
      "version" : "NA",
      "description" : "No description found.",
      "url" : "/_plugin/bigdesk/",
      "jvm" : false,
      "site" : true
    }, {
      "name" : "analysis-ik",
      "version" : "${project.version}",
      "description" : "ik analysis",
      "jvm" : true,
      "site" : false
    }, {
      "name" : "sql",
      "version" : "NA",
      "description" : "Use sql to query elasticsearch.",
      "url" : "/_plugin/sql/",
      "jvm" : true,
      "site" : true
    } ]
  }
}

PHP 5.5 新增特性

PHP 5.5 新增特性

PHP 5.5的新增特性,请参考PHP手册,主要的特性列表如下:

  1. 新增 Generators (生存器的支持)
    PHP 5.5 通过 yield 关键字添加了对Generators的支持

  2. 新增 finally 关键字
    try-catch块新增finally代码块,不管异常是否抛出都会被执行

  3. foreach 现在支持 list()
    foreach 控制结构现在支持通过 list() 构造将嵌套数组分离到单独的变量

  4. empty() 支持任意表达式
    empty() 现在支持传入一个任意表达式,而不仅是一个变量

  5. array and string 字面量的间接引用
    数组和字符串的字面量可以通过间接引用的方式立即访问单独的元素和字符,不需要再定义额外的变量

  6. 细节修改
    不推荐使用 mysql 函数,推荐使用 PDO 或 MySQLi, 参见前文
    不再支持Windows XP

    可用 MyClass::class 取到一个类的完整限定名(包括命名空间)

namespace Name\Generators{

    function xrange($start,$limit,$step=1){
        for($i=$start;$i<=$limit;$i+=$step){
            yield $i;
        }
    }

    /* 保存在内存中的数组绝不会被创建或返回,也就是生成器只生成和返回现在需要使用的数据,
     大于大数组可以节省内存空间,不需要一次加载大量数据,只用很少的一部分*/

    foreach(xrange(1,9,2) as $odd){
        echo $odd,PHP_EOL;
    }
}


namespace Name\ForeachList{

    $arr = [
       [1,2],
       ['a','b']
    ];

    foreach($arr as list($a,$b)){
        echo $a,"\t",$b,PHP_EOL;
    }
}


namespace Name\Dereferencing{
    echo [1,2,3][0],PHP_EOL;
    echo 'PHP'[0],PHP_EOL;
}

PHP 5.6 新增特性

PHP 5.6 新增特性

PHP 最新稳定版本5.6的新增特性,可以参考 PHP手册。 主要新特性的列表:

  1. 使用数值表达式定义常量
    在之前的 PHP 版本中, 必须使用静态值来定义常量,声明属性以及指定函数参数默认值。 现在你可以使用包括数值、字符串字面量以及其他常量在内的数值表达式来 定义常量、声明属性以及设置函数参数默认值
  2. 使用 ... 运算符定义变长参数函数
    现在可以不依赖 func_get_args(), 使用 ... 运算符 来实现 变长参数函数
  3. 使用 ... 运算符进行参数展开
    在调用函数的时候,使用 ... 运算符, 将 数组 和 可遍历 对象展开为函数参数
  4. 使用 ** 进行幂运算
  5. use function 以及 use const
    use 运算符 被进行了扩展以支持在类中导入外部的函数和常量
  6. phpdbg
    PHP 的 SAPI 模块中实现了一个 交互式调试器,叫做 phpdbg
  7. 默认字符编码
    对于一些字符编码相关的函数,例如 htmlentities(), html_entity_decode() 以及 htmlspecialchars() 使用 default_charset 作为默认字符集。请注意,对于 iconv(现已废弃) 和 mbstring 相关的函数, 如果分别设置了他们的编码, 那么这些对应设置的优先级高于 default_charset。default_charset 的默认值是 UTF-8
  8. php://input 是可重用
    只要你需要,你可以多次打开并读取 php://input。 同时,这个特性使得在处理 POST 的数据的时候, 可以明显降低对于内存的需求量
  9. 大文件上传
    现在可以支持大于 2GB 的文件上传
  10. GMP 支持运算符重载
    GMP 支持运算符重载, 并且造型成数值类型。 这使得使用 GMP 的代码更加直观
  11. 使用 hash_equals() 比较字符串避免时序攻击
    加入 hash_equals() 函数, 以恒定的时间消耗来进行字符串比较, 以避免时序攻击。 比如当比较 crypt() 密码散列值的时候,就可以使用此函数。 (假定你不能使用 password_hash() 和 password_verify(), 这两个函数也可以抵抗时序攻击)
  12. __debugInfo()
    加入 __debugInfo(), 当使用 var_dump() 输出对象的时候, 可以用来控制要输出的属性和值
  13. gost-crypto 散列算法
  14. SSL/TLS 提升
  15. pgsql 异步支持
// 新的常量
const C1 = 1;
const C2 = C1*2;

class MyConst{
    const C3 = C2 + 1;
    const C4 = C1/self::C3;
    const C5 = 'The value is '.self::C3;

    public function fun($args=C1+self::C3){
        return $args;
    }

}

echo (new MyConst)->fun(),PHP_EOL;
echo MyConst::C5;

namespace Name\Args{
    //before PHP 5.6
    function fun(){
        //func_num_args()函数获取函数参数的个数 
        $args = func_num_args(); 
        echo "Number of arguments: ",$args,PHP_EOL;

        for($i=0;$i<$args;$i++){
            //func_get_arg(int)获取某个索引位置的参数值
            echo "Argument ",$i, " is: ",func_get_arg($i),PHP_EOL;
        }

        echo "*********************",PHP_EOL;
        //func_get_args()获取参数列表
        $argv = func_get_args();
        foreach($argv as $key=>$value){
            echo "argument ",$key,": ",$value,PHP_EOL;
        }
    }

    fun(1,2,3);
    fun('a','b','c');

    //PHP 5.6
    // 通过...运算符定义变长参数函数 
    function func(...$params){
        foreach($params as $key=>$value){
            echo "argument ",$key," :",$value,PHP_EOL;
        }
    }


    echo "---------------------------------",PHP_EOL;
    func(1,2,3);
    func('a','b','c');

    $args = [10,11,12,13];
    //使用...运算符进行参数展开(在调用函数的时候,使用...运算符,将数组和可遍历对象展开为函数参数)
    func(...$args);
}

namespace Name\Operation{
    //使用 ** 进行幂运算
    echo 2**3,PHP_EOL;
    echo 2**8,PHP_EOL;
}



namespace Name\Outer{
    const TITLE = 'hello,world';
    function func(){
        echo __FUNCTION__,PHP_EOL;
    }
}

namespace Name\Test{

    //通过use运算符倒入外部的函数和常量
    use const Name\Outer\TITLE; //通过use const 导入常量
    use function Name\Outer\func; //通过use function 导入函数

    echo TITLE,PHP_EOL;
    func();
}

陌生的城市

陌生的城市

2015年3月23号下午5点20分,我踏上了这个陌生的城市的土地。深圳,**离资本注意最近的大陆城市。下车后情不自禁的在深圳北的站台上拍了一张照片。第一感觉就是自己衣服穿多了,不过我还是一直穿着两件衣服。然后坐地铁到宝安中心站,等我一个5年没有见的兄弟来宝安中心站接我。很意外我早到了半个小时,找了一个地方,掏出手机,打开豆瓣阅读的app继续看高晓松老师的《如丧》,看了一段关于大百度关于音乐版权的文字,还拿了google和大百度做比较。不一会我们就见面了,然后在大排档 吃饭回家。

2015年3月24号,我早上9点起床,洗完衣服就决定出去走一走。一个人走在这个陌生的城市里,给我的感觉就是街道很干净,然后绿化覆盖率很大。上午办完银行卡和公交卡后,坐上了去深大的地铁,在深大下车。然后找到了大百度所在的国人通信大厦,溜了一圈。就去了企鹅家的腾讯大厦,发现还挺近的。最后在深大逛了一圈就坐地铁回家了。

可能接下来的很多年我都会在这个城市上班,但是却没有了那种一定要在这边定居的想法,随便了解了一下放假跟北京差不多,基本上我这种小白领是很难想象的。说到这居然有一点小小的伤感,都快三十岁的人了,居然还混成这个样子,以后怎么跟小朋友吹牛?好吧,写到这了,看书,奋斗了。

2015 每天一条 Linux 命令

#2015 每天一条 Linux 命令

1. $ cal -y   # 现实全年的日历,高亮当天

2. $ sudo ntpdate  serverip   #同步时间

3. $ du -a --max-depth=1 | sort -n   #按大小排序子目录

4. $ :%s/<control-VM>//g    #在vim清理^M

5.$find . -type f  -name "*.php"  -exec iconv -f iso-8859-1 -t utf-8 "{}" -o /path/to/destination/"{}" \;   #php文件转utf-8

高效工具集合

1.goaccess GoAccess is a real-time web log analyzer and interactive viewer that runs in a terminal in *nix systems or through your browser.

2015 阅读书单

#2015 阅读书单

阅读改变人生,下面是今年阅读读完的清单,将持续更新,希望完成今年的阅读任务:

1.《参与感》 作者:黎万强 多看阅读

2.《来到地球的第一天》 作者:黄章晋 多看阅读

3.《免费:商业的未来》 作者:克里斯·安德森 多看阅读

4.《哲学家们都干了些什么?》 作者:林欣浩 多看阅读

5.《疯狂的投资》 作者:约翰·S·戈登 纸质书

6.《如丧:我们终于老得可以谈谈未来》 作者:高晓松 豆瓣阅读

7.《颠覆式创新》 作者:李善友 纸质书

8.《鱼羊野史:第1卷》 作者:高晓松 豆瓣阅读

9.《专注:如何应对信息泛滥的当下》 作者:Leo Babauta 多看阅读

10.《清醒思考的艺术》 作者:罗尔夫.多贝里 多看阅读

11.《这个时代的无语与傲慢》 作者:乔治.索罗斯 多看阅读

12.《产品型社群》 作者:李善友 纸质书

13.《互联网世界观》 作者:李善友 纸质书

14.《精益创业方法论》 作者:龚焱 纸质书 2015年4月18号

15.《互联网商规11条》 作者:艾.里斯 劳拉.里斯 纸质书

16.《涂鸦笔记》 作者:mike rohde(迈克.罗笛) 纸质书

17.《技术垄断》 作者:Neil Postman 纸质书

18.《三体 Ⅰ》 作者:刘慈欣 纸质书

19.《三体 Ⅱ》 作者:刘慈欣 纸质书

20.《三体 Ⅲ》 作者:刘慈欣 纸质书

21.《奇点临近》 作者:Ray Kurzweil 纸质书

22.《人类简史》 作者:[以色列]尤瓦尔·赫拉利 多看电子书

23.《耶路撒冷三千年》 作者:[英]西蒙•蒙蒂菲奥里 纸质书

24.《唤醒内在的智慧》 作者:[美]丹•米尔曼 纸质书

25.《极客与团队》 作者: Brian W.Fitzpatrick/ Ben Collins-Sussman 纸质书

26.《我知道你不知道的自己在想什么》 作者: 果壳 微信读书

27.《西方哲学简史》 作者: 伯特兰·罗素 微信读书

28.《一个瑜伽行者的自传》 作者:〔美〕帕拉宏撒·尤迦南达 微信读书

29.《零售的哲学》 作者: 〔日〕铃木敏文 微信读书

30.《做自己》 作者:鬼脚七 多看阅读

31.《诸神记:美国漫画演绎》 作者:Multivac 豆瓣阅读

32.《番茄工作法图解》 作者:Staffan Nöteberg 多看阅读

33.《掘金:互联网+时代创业黄金指南》 作者:腾讯科技频道 微信阅读

34.《把时间当作朋友》 作者: 李笑来 多看阅读

35.《硅谷之谜》 作者:吴军 纸质书

36.《风口上的猪 : 一本书看懂互联网金融》 作者: 肖璟 豆瓣阅读

37.《失控》 作者:[美] 凯文·凯利 微信读书

38.《腾讯方法》 作者: 潘东燕 / 王晓明 豆瓣阅读

39.《从0到1》 作者: 彼得·蒂尔 / 布莱克·马斯特斯 纸质书

40.《斯坦福极简经济学》作者:〔美〕蒂莫西·泰勒 豆瓣阅读

41.《你一定愛讀的極簡歐洲史》 作者:約翰.赫斯特(John Hirst) 微信读书

准备阅读的书籍:

1.《塞莱斯廷预言》
2.《想象另一种可能》
3.《万物简史》

4.《不敢止步》

6.《叫魂》

7.《银河帝国》

8.《理解专业程序员》

10.《自私的基因》

11.《从黎明到衰落》

12.《神话》

PHP 内核预定义常量和魔术常量

PHP 内核预定义常量和魔术常量

echo PHP_VERSION,"\n";

echo PHP_OS,"\n";

echo PHP_SAPI,"\n";

echo PHP_EOL,"\n";

echo PHP_INT_MAX,PHP_EOL;

echo PHP_INT_SIZE,PHP_EOL;

echo DEFAULT_INCLUDE_PATH,PHP_EOL;

echo PEAR_INSTALL_DIR,PHP_EOL;

echo PEAR_EXTENSION_DIR,PHP_EOL;

echo PHP_EXTENSION_DIR,PHP_EOL;

echo PHP_PREFIX,PHP_EOL;

echo PHP_BINDIR,PHP_EOL;

echo PHP_LIBDIR,PHP_EOL;

echo PHP_DATADIR,PHP_EOL;

echo PHP_SYSCONFDIR,PHP_EOL;

echo PHP_LOCALSTATEDIR,PHP_EOL;

echo PHP_CONFIG_FILE_PATH,PHP_EOL;

echo PHP_CONFIG_FILE_SCAN_DIR,PHP_EOL;

echo PHP_SHLIB_SUFFIX,PHP_EOL;

echo PHP_OUTPUT_HANDLER_START,PHP_EOL;

echo PHP_OUTPUT_HANDLER_CONT,PHP_EOL;

echo PHP_OUTPUT_HANDLER_END,PHP_EOL;

echo E_ERROR,PHP_EOL;

echo E_WARNING,PHP_EOL;

echo E_PARSE,PHP_EOL;

echo E_NOTICE,PHP_EOL;

echo E_CORE_ERROR,PHP_EOL;

echo E_CORE_WARNING,PHP_EOL;

echo E_COMPILE_ERROR,PHP_EOL;

echo E_COMPILE_WARNING,PHP_EOL;

echo E_USER_ERROR,PHP_EOL;

echo E_USER_NOTICE,PHP_EOL;

echo E_USER_WARNING,PHP_EOL;

echo E_ALL,PHP_EOL;

echo E_STRICT,PHP_EOL;

echo __LINE__,PHP_EOL;

echo __FILE__,PHP_EOL;

echo __DIR__,PHP_EOL;

echo __FUNCTION__,PHP_EOL;

echo __CLASS__,PHP_EOL;

echo __TRAIT__,PHP_EOL;

echo __METHOD__,PHP_EOL;

echo __NAMESPACE__,PHP_EOL;

个人简历 (求工作)

联系方式


个人信息


工作经历

风行在线技术有限公司 (2012年4月 ~ 至今)

手游运营项目

我带团队负责搭建手游(完美神话)运营相关的系统(支付系统,客服和gm工具系统,推送系统,游戏官网)。我主要负责支付系统的搭建和业务代码的编写,客服和gm工具系统的搭建和基础代码的编写,推送系统api和后端服务的维护,游戏官网项目基础代码的编写。这个项目是我成长最快的一个项目,第一次从无到有去负责一个项目和第一次编写PHP的框架。过程中遇到的困难最印象深刻的就是玩家数据的丢失,这个也是最致命的,最后通过将实现方式从换文件变成http的方式完美的解决了日志丢失的问题。

风行网小视频改版项目

我以scrum master的角色第一次带团队在现有的项目中负责一块独立的业务,对我来说最困难的就是从写好自己的代码到完整的交付一个项目的观念上的转变,以及对团队新人的培养,最后项目在两个月时间完结,转调手游运营项目。

风行移动客户端数据api服务项目(Zeus)

我主要负责业务逻辑api的开发,以及后期改版的一些后端服务的开发。api日均pv 5000万,体会最深的就是高并发、缓存。也接触到了敏捷的开发理念。

天津阳关未来科技(2010年3月 ~ 2011年12月)

crm和cms系统

我在此项目负责业务代码的编写和项目的长期维护,第一次接触web和后台相关的东西,在老师的指导和自己的学习下,毕业前顺利完成交付和交接,挣取了自己一年多的生活费用。

无忧生活网会员中心和支付项目

我在此项目中负责网站 (http://www.51chinese.net) 会员中心前端页面实现和支付宝的集成,第一次接触第三方支付的集成,最后完成并上线投入使用。


技能清单

以下均为我熟练使用的技能

  • Web开发:PHP/Node/Python/Golang
  • Web框架:ThinkPHP/Yii/Django/Revel/Beego
  • Web环境:Linux/Nginx
  • 前端框架:Extjs/Jquery
  • 数据库相关:MySQL/SQLite/Redis/Mongodb/Memcache
  • 版本管理、文档和自动化部署工具:Svn/Git/Composer/Jenkins
  • 单元测试:PHPUnit
  • 开放平台:微博开放平台/微信应用开发

致谢

感谢您花时间阅读我的简历,期待能有机会和您共事。

Elasticsearch 初见

Elasticsearch 初见

一. 安装:
1.安装java sdk 建议jdk 1.8以上
2.获取elasticsearch的压缩包:
wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.4.tar.gz
3.解压 tar zxvf elasticsearch-1.7.4.tar.gz
4.cd elasticsearch-1.7.4
5.修改elasticsearch的配置文件 vim config/elasticsearch.yml
主要修改:
a.集群的名字
cluster.name: elasticsearch-test
b.几点的名字
node.name: "104"
c.访问的host
network.host: cp01-bdg-rp-2015q4-104.epc.baidu.com
d.http的端口
http.port: 8206
6.修改bin/elasticsearch bin/plugin两个文件,增加JAVA_HOME的配置
JAVA_HOME=/home/work/.jumbo/opt/sun-java8
7.修改bin/elasticsearch 增加 ES_HEAP_SIZE
ES_HEAP_SIZE = 512m
8.通过 bin/elasticsearch -d 以服务的形式启动 elasticsearch
9.通过 ps -ef|grep elasticsearch可以看到elasticsearch的进程已经在跑了
[work@cp01-bdg-rp-2015q4-104 elasticsearch-1.7.4]$ ps -ef|grep elasticsearch

work      9985     1 99 13:52 pts/0    00:00:06 /home/work/.jumbo/opt/sun-java8/bin/java -Xms512m -Xmx512m -Djava.awt.headless=true -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError -XX:+DisableExplicitGC -Dfile.encoding=UTF-8 -Delasticsearch -Des.path.home=/home/work/elastic_sers/elasticsearch-1.7.4 -cp :/home/work/elastic_sers/elasticsearch-1.7.4/lib/elasticsearch-1.7.4.jar:/home/work/elastic_sers/elasticsearch-1.7.4/lib/*:/home/work/elastic_sers/elasticsearch-1.7.4/lib/sigar/* org.elasticsearch.bootstrap.Elasticsearch

二. 一些http接口的使用
1.通过http链接:http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/ 可以看到node的一些信息

{
  "status" : 200,
  "name" : "104",
  "cluster_name" : "elasticsearch-test",
  "version" : {
    "number" : "1.7.4",
    "build_hash" : "0d3159b9fc8bc8e367c5c40c09c2a57c0032b32e",
    "build_timestamp" : "2015-12-15T11:25:18Z",
    "build_snapshot" : false,
    "lucene_version" : "4.10.4"
  },
  "tagline" : "You Know, for Search"
}

2.通过http链接:http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/_cluster/health?pretty 可以查看集群的健康信息

{
  "cluster_name" : "elasticsearch-test",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 0,
  "active_shards" : 0,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0
}

3.通过http链接:http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/_cluster/stats?pretty 可以看到集群更详细的信息

{
  "timestamp" : 1452664808338,
  "cluster_name" : "elasticsearch-test",
  "status" : "green",
  "indices" : {
    "count" : 0,
    "shards" : { },
    "docs" : {
      "count" : 0,
      "deleted" : 0
    },
    "store" : {
      "size_in_bytes" : 0,
      "throttle_time_in_millis" : 0
    },
    "fielddata" : {
      "memory_size_in_bytes" : 0,
      "evictions" : 0
    },
    "filter_cache" : {
      "memory_size_in_bytes" : 0,
      "evictions" : 0
    },
    "id_cache" : {
      "memory_size_in_bytes" : 0
    },
    "completion" : {
      "size_in_bytes" : 0
    },
    "segments" : {
      "count" : 0,
      "memory_in_bytes" : 0,
      "index_writer_memory_in_bytes" : 0,
      "index_writer_max_memory_in_bytes" : 0,
      "version_map_memory_in_bytes" : 0,
      "fixed_bit_set_memory_in_bytes" : 0
    },
    "percolate" : {
      "total" : 0,
      "time_in_millis" : 0,
      "current" : 0,
      "memory_size_in_bytes" : -1,
      "memory_size" : "-1b",
      "queries" : 0
    }
  },
  "nodes" : {
    "count" : {
      "total" : 1,
      "master_only" : 0,
      "data_only" : 0,
      "master_data" : 1,
      "client" : 0
    },
    "versions" : [ "1.7.4" ],
    "os" : {
      "available_processors" : 4,
      "mem" : {
        "total_in_bytes" : 16729292800
      },
      "cpu" : [ {
        "vendor" : "Intel",
        "model" : "Xeon",
        "mhz" : 1995,
        "total_cores" : 4,
        "total_sockets" : 4,
        "cores_per_socket" : 1,
        "cache_size_in_bytes" : 4096,
        "count" : 1
      } ]
    },
    "process" : {
      "cpu" : {
        "percent" : 0
      },
      "open_file_descriptors" : {
        "min" : 157,
        "max" : 157,
        "avg" : 157
      }
    },
    "jvm" : {
      "max_uptime_in_millis" : 466140,
      "versions" : [ {
        "version" : "1.8.0_45",
        "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
        "vm_version" : "25.45-b02",
        "vm_vendor" : "Oracle Corporation",
        "count" : 1
      } ],
      "mem" : {
        "heap_used_in_bytes" : 111662104,
        "heap_max_in_bytes" : 518979584
      },
      "threads" : 45
    },
    "fs" : {
      "total_in_bytes" : 166418821120,
      "free_in_bytes" : 90759639040,
      "available_in_bytes" : 82169704448,
      "disk_reads" : 4290291,
      "disk_writes" : 27912327,
      "disk_io_op" : 32202618,
      "disk_read_size_in_bytes" : 332086834176,
      "disk_write_size_in_bytes" : 1995287842816,
      "disk_io_size_in_bytes" : 2327374676992,
      "disk_queue" : "0",
      "disk_service_time" : "0"
    },
    "plugins" : [ {
      "name" : "bigdesk",
      "version" : "NA",
      "description" : "No description found.",
      "url" : "/_plugin/bigdesk/",
      "jvm" : false,
      "site" : true
    } ]
  }
}

4.[增] 通过http接口写入数据到 index:test type:stu
a.写入一条信息
post http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/1 -d '{"name":"name1","age":25}'
通过postman的截图
image
返回值:

{
  "_index": "test",
  "_type": "stu",
  "_id": "1",
  "_version": 1,
  "created": true
}

b.一次写入多条数据
post http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/_bulk -d
'{"index":{"_id":2}}
{"name":"name2","age":21}
{"index":{"_id":3}}
{"name":"name3","age":21}
{"index":{"_id":4}}
{"name":"name4","age":21}
'
b. 通过postman的截图
image
[每条数据有两行组成,index行指定数据的_id的值,类似表的主键,紧挨着的行是写入指定index的数据字符json格式的每一行需要\n换行,最后一行也不例外]
返回值:

{
  "took": 11,
  "errors": false,
  "items": [
    {
      "index": {
        "_index": "test",
        "_type": "stu",
        "_id": "2",
        "_version": 1,
        "status": 201
      }
    },
    {
      "index": {
        "_index": "test",
        "_type": "stu",
        "_id": "3",
        "_version": 1,
        "status": 201
      }
    },
    {
      "index": {
        "_index": "test",
        "_type": "stu",
        "_id": "4",
        "_version": 1,
        "status": 201
      }
    }
  ]
}

5.[查] 通过http接口获取 index:test type:stu的数据
a.通过_id获取一条数据
get http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/1
返回值:

{"_index":"test","_type":"stu","_id":"1","_version":1,"found":true,"_source":{"name":"name1","age":25}}

b.获取所有的数据,默认返回10条
get http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/_search
返回值:

{"took":7,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"test","_type":"stu","_id":"4","_score":1.0,"_source":{"name":"name4","age":21}},{"_index":"test","_type":"stu","_id":"1","_score":1.0,"_source":{"name":"name1","age":25}},{"_index":"test","_type":"stu","_id":"2","_score":1.0,"_source":{"name":"name2","age":21}},{"_index":"test","_type":"stu","_id":"3","_score":1.0,"_source":{"name":"name3","age":21}}]}}

c.查询的以后再说

6.[改] 通过http接口修改 index:test type:stu的数据
a.修改某个字段的值
put http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/1 -d '{"name":"name1", "age":15}'
修改年龄为15的返回值:

{
  "_index": "test",
  "_type": "stu",
  "_id": "1",
  "_version": 2,
  "created": false
}

b.通过bulk接口只指定要修改的字段
post http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/_bulk -d
'{"update":{"_id":1}}
{"doc":{"age":13}}'
修改年龄为13的返回值:

{
  "took": 7,
  "errors": false,
  "items": [
    {
      "update": {
        "_index": "test",
        "_type": "stu",
        "_id": "1",
        "_version": 3,
        "status": 200
      }
    }
  ]
}
``` json
c.通过bulk接口修改多条记录的相关字段
post http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/_bulk -d
'{"update":{"_id":2}}
{"doc":{"age":13}}
{"update":{"_id":3}}
{"doc":{"age":13}}
'
修改年龄为13的返回值:
``` json
{
  "took": 6,
  "errors": false,
  "items": [
    {
      "update": {
        "_index": "test",
        "_type": "stu",
        "_id": "2",
        "_version": 2,
        "status": 200
      }
    },
    {
      "update": {
        "_index": "test",
        "_type": "stu",
        "_id": "3",
        "_version": 2,
        "status": 200
      }
    }
  ]
}

d.通过bulk给多条记录增加字段
post http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/_bulk -d
'{"update":{"_id":2}}
{"doc":{"gender":"男"}}
{"update":{"_id":3}}
{"doc":{"gender":"女"}}
{"update":{"_id":1}}
{"doc":{"gender":"女"}}
'
添加gender字段后的返回值:

{
  "took": 16,
  "errors": false,
  "items": [
    {
      "update": {
        "_index": "test",
        "_type": "stu",
        "_id": "2",
        "_version": 3,
        "status": 200
      }
    },
    {
      "update": {
        "_index": "test",
        "_type": "stu",
        "_id": "3",
        "_version": 3,
        "status": 200
      }
    },
    {
      "update": {
        "_index": "test",
        "_type": "stu",
        "_id": "1",
        "_version": 10,
        "status": 200
      }
    }
  ]
}

7.[删] 通过http接口删除 index:test type:stu的数据
a.删除单条数据
delete http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/4
返回值:

{
  "found": true,
  "_index": "test",
  "_type": "stu",
  "_id": "4",
  "_version": 2
}

b.通过bulk接口一次删除多条数据
post http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/test/stu/_bulk -d
'{"delete":{"_id":2}}
{"delete":{"_id":3}}
'
返回值:

{
  "took": 1,
  "errors": false,
  "items": [
    {
      "delete": {
        "_index": "test",
        "_type": "stu",
        "_id": "2",
        "_version": 4,
        "status": 200,
        "found": true
      }
    },
    {
      "delete": {
        "_index": "test",
        "_type": "stu",
        "_id": "3",
        "_version": 4,
        "status": 200,
        "found": true
      }
    }
  ]
}

8.查看所有的index
get http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/_cat/indices?v
返回值

health status index pri rep docs.count docs.deleted store.size pri.store.size 
yellow open   info    5   1          3            0      7.9kb          7.9kb 
yellow open   test    5   1          1            0      3.3kb          3.3kb 

9.查看集群的健康状态
get http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/_cat/health?v
返回值

epoch      timestamp cluster            status node.total node.data shards pri relo init unassign pending_tasks 
1452668795 15:06:35  elasticsearch-test yellow          1         1     10  10    0    0       10             0 

三.插件
1.bigdesk node节点监控 [http://bigdesk.org/]
a.安装
在elasticsearch-1.7.4的目录中运行下面的安装命令
./bin/plugin install lukas-vlcek/bigdesk
b.重启elasticsearch服务器
c.通过http链接: http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/_plugin/bigdesk/#nodes
d.插件运行的截图
image

2.elasticsearch-sql 查询,使用sql语法查询elasticsearch [https://github.com/NLPchina/elasticsearch-sql]
a.获取elasticsearch-sql的安装包zip文件
wget https://github.com/NLPchina/elasticsearch-sql/releases/download/1.4.7/elasticsearch-sql-1.4.7.zip -O elasticsearch-sql-1.4.7.zip
b.本地安装
./bin/plugin -u file:///home/work/elastic_sers/elasticsearch-1.7.4/plugin-zips/elasticsearch-sql-1.4.7.zip --install sql
c.重启elasticsearch服务器
d.通过http链接:http://cp01-bdg-rp-2015q4-104.epc.baidu.com:8206/_plugin/sql/
e.插件运行的截图
image

互联网大会

翻看了一下去年写的东西,发现有一篇写互联网大会的文章,世界互联网大会,居然过了一年了。今年的互联网大会,除了关注我厂的自动驾驶汽车外,多部分时间就是各种黑换联网大佬。不过今天的一张图看懂互联网大佬的英语水平,明显海龟的大佬们优势明显。国内的土生大佬们就是稍微要差一些,一个特例就是东哥,出去学习了一年带回个妹子,英语还是没啥涨进。

最近看了一本书《腾讯方法》里面那个讲手游项目的文字对我触动蛮大。毕竟我也做过一年多的手游,除了晚上12点之前没有人回家比较吓人外,其他的满满的都是专业和正能量。不过最近腾讯互娱一个组长猝死的事情,还是请各位IT行业的工程师们珍爱生命,远离加班。不要报任何侥幸的心理,觉得自己很强壮,年轻扛得住什么的,老想着这种事情不会发生在自己的身上。任何人都不能保证明天和意外哪一个先来。

这两周项目需要要灌一批亿级的数据,用户检索和统计。考虑了一下之后觉得用elasticsearch来做存储和检索。灌数据这个事情,自己折腾了自己好久。主要是两个原因:1.觉得说php速度太慢了 2.觉得说用go开携程可能会快很多。php做了一个初始的版本,不需要用很严格的schema,就是读文件,拼接成array转json然后批量入elasticsearch就好了。我也不知道为什么当时会想说go可能会快一些,然后就花了点时间写了一个go版的。定义一个struct,读文件然后填充struct的obj接着把obj做json的encode然后批量灌elasticsearch。但是出现了两个问题:1.struct的属性字段明必须大写,不然json encode的时候导出不了;2.因为数据的shema是不固定的,导致会抹掉一些属性之外的字段。果断放弃,老老实实把php的代码改了两版开几个php进程一起灌数据。后来自己一直在考虑一个问题:为什么我一开始不想着优化php的代码,而想着换别的我认为性能比较好的语言重新实现 ?

一种api文档的markdown样式

请注意:

Viva数据接口的说明:

1.线上环境域名:viva.baidu.com/visdata.baidu.com
2.测试环境域名:cp01-bdg-rp-2015q4-104.epc.baidu.com:8080

1.用户注册接口

用于viva产品的用户的注册,以便于后面用户的登录和使用viva产品

接口调用请求说明
http请求方式: POST
http://viva.baidu.com/api/register?userName=USER_NAME&password=PASSWORD
调用示例:使用curl命令,用FORM表单格式传递数据,curl命令的具体用法请自行了解
参数说明
参数 是否必须 说明
userName 用户登录viva将使用的用户名,最长32个字符
password 用户登录viva将使用的与用户名匹配的密码,最长32个字符
返回说明

正常情况下返回的结果为:

{
    "status": 0,
    "info": "",
    "data": ""
}

错误情况下返回的结果为:

{
    "status": ErrorNO,
    "info": "ErrorInfo",
    "data": ""
}
错误码说明

错误码说明请参考 全局错误码

PHP 命令行

PHP 命令行

➜  /home/smilefish1987/php  > php -h
Usage: php [options] [-f] <file> [--] [args...]
   php [options] -r <code> [--] [args...]
   php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]
   php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]
   php [options] -S <addr>:<port> [-t docroot]
   php [options] -- [args...]
   php [options] -a

  -a               Run interactively
  -c <path>|<file> Look for php.ini file in this directory
  -n               No php.ini file will be used
  -d foo[=bar]     Define INI entry foo with value 'bar'
  -e               Generate extended information for debugger/profiler
  -f <file>        Parse and execute <file>.
  -h               This help
  -i               PHP information
  -l               Syntax check only (lint)
  -m               Show compiled in modules
  -r <code>        Run PHP <code> without using script tags <?..?>
  -B <begin_code>  Run PHP <begin_code> before processing input lines
  -R <code>        Run PHP <code> for every input line
  -F <file>        Parse and execute <file> for every input line
  -E <end_code>    Run PHP <end_code> after processing all input lines
  -H               Hide any passed arguments from external tools.
  -S <addr>:<port> Run with built-in web server.
  -t <docroot>     Specify document root <docroot> for built-in web server.
  -s               Output HTML syntax highlighted source.
  -v               Version number
  -w               Output source with stripped comments and whitespace.
  -z <file>        Load Zend extension <file>.

  args...          Arguments passed to script. Use -- args when first argument
                   starts with - or script is read from stdin

  --ini            Show configuration file names

  --rf <name>      Show information about function <name>.
  --rc <name>      Show information about class <name>.
  --re <name>      Show information about extension <name>.
  --rz <name>      Show information about Zend extension <name>.
  --ri <name>      Show configuration for extension <name>.

PHP 5.3 新增特性

PHP 5.3 新增特性

PHP 5.3 新增特性请参考 PHP手册,新增特性列表如下:

  1. 添加了命名空间的支持.
    从广义上来说,命名空间是一种封装事物的方法。
    在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:
    a.用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突
    b.为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性
    PHP 命名空间提供了一种将相关的类、函数和常量组合到一起的途径
  2. 添加了静态晚绑定支持.
    自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。
    当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。所谓的“转发调用”(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。可用 get_called_class() 函数来得到被调用的方法所在的类名,static:: 则指出了其范围。“后期绑定”的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。
  3. 添加了跳标签支持.
  4. 添加了原生的闭包(Lambda/匿名函数)支持.
  5. 新增了两个魔术方法, __callStatic 和 __invoke.
  6. 添加了 Nowdoc 语法支持, 类似于 Heredoc 语法, 但是包含单引号.
  7. 使用 Heredoc 来初始化静态变量和类属性/常量变为可能.
  8. 可使用双引号声明 Heredoc, 补充了 Nowdoc 语法.
  9. 可在类外部使用 const 关键词声明 常量.
  10. 三元运算操作符有了简写形式: ?:.
  11. HTTP 流包裹器将从 200 到 399 全部的状态码都视为成功。
  12. 动态访问静态方法变为可能.
  13. 异常可以被内嵌.
  14. 新增了循环引用的垃圾回收器并且默认是开启的.
  15. mail() 现在支持邮件发送日志. (注意: 仅支持通过该函数发送的邮件.)
/* 1.虽然任意合法的PHP代码都可以包含在命名空间中,但只有三种类型的代码受命名空间的影响,它们是:类,函数和常量
   2.命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间
   3.在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。另外,所有非 PHP 代码包括空白符
   都不能出现在命名空间的声明之前
   4.同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中
   5.可以在同一个文件中定义多个命名空间*/

//方式一定义多个命名空间
namespace MyNamespace;

const OK = 1;
class Test{

    public function test(){
        echo "Test->test()",PHP_EOL;
    }
}

function test(){
    echo "test",PHP_EOL;
}

// PHP 命名空间也允许指定层次化的命名空间的名称
namespace Name\MyNamespace;

const OK = 1;
class Test{

  public function test(){
    echo "Test->test()",PHP_EOL;
  }
}

function test(){
  echo "test",PHP_EOL;
}


//方式二定义多个命名空间,推荐使用大括号的方式在同一个文件中定义多个命名空间
namespace MyNamespace{

  const OK = 1;
  class Test{

    public function test(){
      echo "Test->test()",PHP_EOL;
    }
  }

  function test(){
    echo "test",PHP_EOL;
  }
}

// PHP 命名空间也允许指定层次化的命名空间的名称
namespace Name\MyNamespace{

  const OK = 1;
  class Test{

    public function test(){
      echo "Test->test()",PHP_EOL;
    }
  }

  function test(){
    echo "test",PHP_EOL;
  }
}


/* 1.在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。
   2.将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的
   namespace 语句加上大括号括起来
   3.除了开始的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();
}


namespace Foo\Bar\Sub{
    const FOO = 1;
    function foo(){
      echo "Foo|Bar|Sub|foo()",PHP_EOL;
    }

    class foo{
      static function func(){
         echo "Foo|Bar|Sub|foo|func()",PHP_EOL;
      }
    }

}


namespace Foo\Bar{
    const FOO = 2;
    function foo(){
       echo "Foo|Bar|foo()",PHP_EOL;
    }

    class foo{
       static function func(){
          echo "Foo|Bar|foo|func()",PHP_EOL;
       }
    }

    foo();    // Foo|Bar|foo()
    foo::func(); // Foo|Bar|foo|func()
    echo FOO,PHP_EOL;   // 2

    echo "*************************",PHP_EOL;
    Sub\foo();  // Foo|Bar|Sub|foo()
    Sub\foo::func();  // Foo|Bar|Sub|foo|func()
    echo Sub\FOO,PHP_EOL; // 1

    echo "++++++++++++++++++++++++++",PHP_EOL;
    \Foo\Bar\foo();   // Foo|Bar|foo()
    \Foo\Bar\foo::func(); // Foo|Bar|foo|func()
    echo \Foo\Bar\FOO,PHP_EOL;  // 2

    //注意访问任意全局类、函数或常量,都可以使用完全限定名称
    echo \strlen("hello,world!"),PHP_EOL;
}


/* PHP 命名空间的实现受到其语言自身的动态特征的影响,必须使用完全
限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或
常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的 */

namespace NameSpaceTest;

class ClassName{
   function __construct(){
      echo __METHOD__,PHP_EOL;
   }
}

function funcname(){
    echo __FUNCTION__,PHP_EOL;
}

const constname = "namespaced";

//$a = 'ClassName';  //报错
$a = '\NameSpaceTest\ClassName';
$obj = new $a;
$a2 = 'NameSpaceTest\ClassName';
$obj2 = new $a2;
//$b = 'funcname';  //报错
$b = '\NameSpaceTest\funcname';
$b2 = 'NameSpaceTest\funcname';
$b();
$b2();
//echo constant('constname'),PHP_EOL; // warnning
echo constant('\NameSpaceTest\constname'),PHP_EOL;
echo constant('NameSpaceTest\constname'),PHP_EOL;


/* 1.PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__ 魔术常量和
    namespace关键字
   2.常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名
    空间中的代码,它包含一个空的字符串。
   3.常量 __NAMESPACE__ 在动态创建名称时很有用
   4.关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。它等价于类中
     的 self 操作符 */

namespace MyProject1{
    echo __NAMESAPCE__,PHP_EOL;

}

namespace MyProject2{
   function get($className){
      $a = __NAMESPACE__.'\\'.$className;
      return new $a;
   }
}

namespace MyProject3{
  // see "Using namespaces: importing/aliasing"
  use blah\blah as mine;

  // calls function MyProject\blah\mine()
  blah\mine();

  // calls function MyProject\blah\mine()
  namespace\blah\mine();

  // calls function MyProject\func()
  namespace\func();
  // calls function MyProject\sub\func()
  namespace\sub\func();
  // calls static method "method" of class MyProject\cname
  namespace\cname::method();
  // instantiates object of class MyProject\sub\cname
  $a = new namespace\sub\cname();

  // assigns value of constant MyProject\CONSTANT to $b
  $b = namespace\CONSTANT;
}

/* 1.允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征
   2.PHP 命名空间支持 有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名
   3.PHP不支持导入函数或常量
   4.在PHP中,别名是通过操作符 use 来实现的 */

namespace foo{
   use My\Full\ClassName as Another;

   use My\Full\NSname;

   use \ArrayObject;

   // 实例化 foo\Another 对象
   $obj = new namespace\Another;

   // 导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是
   // 实例化 My\Full\Classname 对象
   $obj = new Another;
   //实例化一个 Another类的对象
   $name = 'Another';
   $obj1 = new $name;

   // 调用函数 My\Full\NSname\subns\func
   NSname\subns\func();

   // 实例化 ArrayObject 对象
   //// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
   $a = new ArrayObject(array(1));

   /* 注意对命名空间中的名称(包含命名空间分隔符的完全限定名称如 Foo\Bar以及相对的不包含
    命名空间分隔符的全局名称如 FooBar)来说,前导的反斜杠是不必要的也不允许有反斜杠,因为
    导入的名称必须是完全限定的,不会根据当前的命名空间作相对解析 */
   // 导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
   //为了简化操作,PHP还支持在一行中使用多个use语句
   use My\Name as Myn,My\Full\Name;
}


/* 如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念
  前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中
  时也是如此。 */

namespace A\B\C{
  function fopen(){
     $f = \fopen(...); //调用全局函数 fopen();
     return $f;
  }
}


/* 在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的
   优先策略来解析该名称。类名称总是解析到当前命名空间中的名称。因此在访问系统内部
   或不包含在命名空间中的类名称时,必须使用完全限定名称 */

namespace A\B\C;
class Exception extends \Exception {}

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

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

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

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

namespace A\B\C{

  const E_ERROR = 45;
  function strlen($str)
  {
   return \strlen($str) - 1;
  }

  echo E_ERROR, "\n"; // 输出 "45"
  echo INI_ALL, "\n"; // 输出 "7" - 使用全局常量 INI_ALL

  echo strlen('hi'), "\n"; // 输出 "1"
  if (is_array('hi')) { // 输出 "is not array"
   echo "is array\n";
  } else {
   echo "is not array\n";
  }
}

/* 命名空间名称定义
非限定名称Unqualified name
名称中不包含命名空间分隔符的标识符,例如 Foo

限定名称Qualified name
名称中含有命名空间分隔符的标识符,例如 Foo\Bar

完全限定名称Fully qualified name
名称中包含命名空间分隔符,并以命名空间分隔符开始的标识符,例如 \Foo\Bar。
namespace\Foo 也是一个完全限定名称。 */

//名称解析遵循下列规则
/*
1.对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。
2.所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。
3.在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。
4.非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。
5.在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:
  a.在当前命名空间中查找名为 A\B\foo() 的函数
  b.尝试查找并调用 全局(global) 空间中的函数 foo()。
6.在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程: new C()的解析:
  a.在当前命名空间中查找A\B\C类。
  b.尝试自动装载类A\B\C。
7.new D\E()的解析:
  a.在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
  b.尝试自动装载类 A\B\D\E。
为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C() */

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" 中定义的类 "B" 的 "foo" 方法
  // 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
}


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

    class A{
        public static function who(){
            echo __CLASS__,PHP_EOL;
        }

        public static function test(){
            self::who();
        }
    }

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

    B::test();
}

/* 后期静态绑定本想通过引入一个新的关键字表示运行时最初调用的类来绕过限制。
简单地说,这个关键字能够让你在上述例子中调用 test() 时引用的类是 B 而不是 A。
最终决定不引入新的关键字,而是使用已经预留的 static 关键字 */

namespace StaticTest1{
   class A{
      public static function who(){
          echo __CLASS__,PHP_EOL;
      }

      public static function test(){
          static::who();
      }

   }

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

   B::test();
}


/* 在非静态环境下,所调用的类即为该对象实例所属的类。由于 $this-> 会在同一作用
   范围内尝试调用私有方法,而 static:: 则可能给出不同结果。另一个区别是
   static:: 只能用于静态属性 */

namespace StaticTest2{
    class A{
       private function foo(){
          echo "success!",PHP_EOL;
       }

       public function test(){
          $this->foo();
          static::foo();
       }
    }

    class B extends A{

    }

    class C extends A{
       private function foo(){

       }
    }

    $b = new B();
    $b->test();

    $c = new C();
    //$c->test();  // fails, Fatal error
}

/* 后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。另一方面,如果静态调用使用
   parent:: 或者 self:: 将转发调用信息 */

namespace staticTest3{
  class A {
     public static function foo(){
        static::who();
     }

     public static function who(){
        echo __CLASS__,PHP_EOL;
     }

  }

  class B extends A{
     public static function test(){
        A::foo();
        parent::foo();
        self::foo();
     }

     public static function who(){
        echo __CLASS__,PHP_EOL;
     }
  }

  class C extends B{
     public static function who(){
        echo __CLASS__,PHP_EOL;
     }
  }

  C::test();
}

新的开始

新的开始

2015年来了,介于2014年用hexo实现的一个github pages的静态blog文件太多每次都需要更新很多的文件,而且文章不带评论和回复的功能,所有今年把博客用github issues的形式进行更新。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.