2011年12月27日 星期二

[PHP] 如何使用 Onion 建置 PEAR 套件

以往要建置 PEAR 套件,得先研究 package.xml 的規格,然後使用一個超過 200 多行的樣板一行一行修改,若是檔案一多,更是麻煩。
因此 Onion https://github.com/c9s/Onion 是為了解決 PEAR 套件建置所提供的方案。
首先請確認你的程式碼目錄結構
  • src/ 類別目錄
  • doc/ 文件目錄
  • tests/ 單元測試目錄
你的類別名稱與名稱空間需要遵守 PSR-0 的規範,例如以下的類別:
<?php
namespace Foo;
class Bar {
}
應該被放置在 src/Foo/Bar.php 檔案中。
測試相關的檔案可放置於 tests/,一般來說都是使用 PHPUnit 作為測試框架,你也可以使用 PHPUnit_TestMore 來幫助你簡化測試程式碼。
接著即可建立 package.ini 來建置 PEAR 套件。
於套件目錄下,編輯 package.ini 檔案
[package]
name = PacakgeName
version = 0.0.1
desc = description here
summary = summary here
author = Author Name <your_email@email.com>
如果你的套件相依其他 PEAR 模組,可接著定義:
[require]
pear.twig-project.org/Twig = 1.0.1
格式為:
{PEAR Channel Host}/{Package Name} = {Version Expression}
接著,將 Onion.phar 抓取下來裝置於你的系統中:
$ wget https://github.com/c9s/Onion/raw/master/onion.phar
$ chmod +x onion.phar
$ ./onion.phar -d build
即可建置 PEAR 套件檔案。 PackageName-0.0.1.tgz 就會被產生出來。
你也可以透過 PEAR Installer 直接安裝該套件:
$ sudo pear install -f package.xml
若你希望將相依性安裝至該套件目錄,且不需要 root 權限,你可以執行:
$ ./onion.phar -d bundle 
相依套件就會被安裝至 vendor/pear 內。
Onion on GitHub: https://github.com/c9s/Onion

2011年12月25日 星期日

[PHP] Onion For PEAR: 發佈 Onion 0.0.10 bundle 功能


我們目前釋出了 Onion 0.0.10-alpha 的版本,這個版本包含了 bundle 的功能,可以將 PEAR 的相依套件安裝至目前目錄的 vendor 目錄底下,且不需要相依 PEAR Installer 或是 Pyrus。

你可以在 package.ini 內定義好 PEAR 套件的所有相依性,然後執行 onion.phar -d bundle 的命令,Onion 會將所有套件安裝至本地目錄下,且不需要 Root 權限就可以做到。

目前,Onion 是利用 bundle 指令,將 Onion 自己的相依套件全部安裝至 vendor/pear ,然後使用 Onion 自己的 compile 命令,將本身程式碼、相依程式碼、自動類別載入器打包成 phar 的執行檔。

你也可以使用 Onion 來編譯你自己的 phar 函式庫或是執行檔。你可以參考原始碼內的 scripts/compile.sh 命令。

因為 Pyrus 沒有把 Package.xml 剖析器類別、PEAR 頻道探索器等文件寫好,也因為他不是獨立的元件,所以我為 Onion 寫了一個內建的 PEAR 頻道探索器 (PEAR Channel) 以及簡單的 package.xml 剖析器,來處理 PEAR 套件的安裝程序。 這些東西運作的相當快,不過 Channel 的資訊還未被快取起來,只要快取的部份處理好後,速度會比現在更快。

我已經測試了一些 Symfony, PHPUnit, PHPSpec, PEAR 套件,大多數都運作的挺順利,但是可能還有一些 Bug ,如果你遇到了,請發送一個 Issue 給我,Onion 專案是建置在 GitHub 上頭。

Patches, Feature requests are welcomed.


Here is the screenshot:




Related Tweets:

https://twitter.com/#!/yuya_takeyama/status/150642017003778050
https://twitter.com/#!/yuya_takeyama/status/150627664917577728
https://twitter.com/#!/yuya_takeyama/status/150619889244180481

Onion For PHP: Announcing Onion 0.0.10 bundle feature

We currently released Onion 0.0.10-alpha, this version introduced a bundle feature, which can install PEAR package dependencies into a vendor directory.

You can define your PEAR package dependencies in package.ini, and run onion.phar -d bundle, onion will install dependencies locally, and root permission is not needed.

Currently, Onion is using bundle command to install Onion's dependencies, and run onion compile command to compile src/, vendor/pear/ and a SPLClassLoader into a phar file.

You can also use Onion to compile your library into a plain library phar file or executable phar file, you can check the script "scripts/compile.sh".

Since Pyrus didn't document much of its PackageXml parser and Channel Discover, and it's not independent component, I wrote a built-in PEAR channel discover and a simple package.xml parser for this, which is pretty fast already. but the channel information is not cached yet. Once the cache stuff is done, this could be more faster than current one.

I've tested many PEAR packages from Symfony, PHPUnit, PHPSpec, most of them works fine, but may have some bugs still, If you encountered, please send an issue on GitHub/Onion repository.

Onion project is hosted on GitHub, patches and feature request are welcomed.

Here is the screenshot:




Related Tweets:

https://twitter.com/#!/yuya_takeyama/status/150642017003778050
https://twitter.com/#!/yuya_takeyama/status/150627664917577728
https://twitter.com/#!/yuya_takeyama/status/150619889244180481

2011年12月24日 星期六

Access 97, ODBC, unixODBC, iODBC, mdbtools 問題處理記錄

今天處理 Microsoft Access Database 的問題就花上了一整天 ...

簡單介紹一下該死的 MS Access Database (*.mdb) 是微軟發展的資料庫引擎,從 Access 97 使用 Jet 3.5 版本,從 Access 2000 時則採用 Jet 4.0 版本。

可以在 DSN 時指定 Provider 參數 Provider=Microsoft.Jet.OLEDB.4.0 指定 Jet OLEDB 的版本。


而在 Unix 系統上大致上有多款 Jet Database Engine 的實作 (應該是反向工程而來的) ,譬如:


首先 mdbtools 是由 C 寫成,可讀取 Access 97 版本以上的 mdb 檔案,不過在編碼的部份有點問題,若 Access 97 內使用 Big5 ,似乎沒辦法順利透過 mdbtools 提供的 charset 環境變數來指定,程式碼中使用到 iconv 的環境變數有:

MDBICONV=UTF-8
MDB_JET3_CHARSET=Big-5

該 JET3_CHARSET 為資料庫編碼,MDBICONV 為內部編碼,但這個解法無效,頂多只能讀出 Table 以及各 Table 資料內的比數,但由於 Access DB 的開發人員相當蠢,直接用 Big5 編碼的字元當做 Table Name ,所以無效。

後來也嘗試使用 mdbtools 將讀取出的 Table Name 利用 mbstring convert encoding 試著從 Big5 轉為 UTF-8 ,但這條路也不通,但讀出的字元是 ASCII 沒錯 (should be Big-5),這部份不知道是否有長輩有解答 ?

但我想只要該 DB 內資料若使用 ASCII 或是 ISO8859-1 的話應該是可以運作順利。

Jackcess 主要由 Java 所寫成,目前看起來可靠度最高,但是不支援 Access 97 以下版本,除此之外其他的 Jet Database 都支援,程式碼內也有 junit 所寫成的單元測試,測試各種格式的資料庫版本,不過因為不支援 Access 97 ,所以沒有繼續嘗試,否則應該是很好的跨平台解決方案。



資料庫介面的部份可以透過 ODBC 或是 iODBC 或是 Windows 上的 COM 元件來建立 ADODB 連線來讀取 Access Database 的資料庫,也可透過 ActiveXObject 建立 ADODB 連線。

不幸的地方在於,Unix 上的 mdbtools 既然無法運作正確,再接著用 ODBC 指定 Driver 為 mdbtools 也無用了。 否則應該是可以透過下列方式連結:

// With DSN
$connection = odbc_connect("access_db",'','');

// For Windows, DSN-less
$connection = odbc_connect("Driver={Microsoft Access Driver (*.mdb)};Dbq=$mdbFilename", $user, $password);

不過 ODBC 的部份光是指定 mdbtools 連連線都有問題。


接著嘗試使用 Windows 7 64bit 建立連至 Access 97 mdb 檔案的 ODBC 連線,發現 Jet Database Engine 並不支援 64bit Windows 7 ,有看到大概的解法,但我嘗試過也不行:

C:\Windows\SysWow64\odbcad.exe

所以只好轉而裝個 Virutalbox Windows XP 建立 ODBC 連線,連線沒問題,但同樣也卡在編碼。

整個 Google 都快翻過來的沒看到任何可以對 Access *.mdb 指定 CodePage 或是 Charset 的方法,或是嘗試了完全無效。

總之嘗試了以下大概幾種:

* Windows PHP 內的 COM 元件建立 ADODB.Connection
* JScript 使用 ActiveXObject 建立 ADODB.Connection
* PHP odbc_connect 連線

這三種途徑在 Windows XP 32bit 上都可順利連線,取得資料表清單,但仍是有編碼問題。

也就是說,就算是用微軟自己的 JScript (CScript) 都沒辦法正確讀出字元

推測大概還有幾種解決方法:

- 使用 Access 2010 把 Access 97 轉為較新版本的 mdb。
- 使用 MySQL Migration Toolkit 轉匯入至 MySQL (不過在新版的 MySQL 內卻找不到 Migration Toolkit 了,是否有分割出來 ? )

但我想編碼的方式應該還是有辦法解決,只是時間上的問題罷了。XD






2011年12月19日 星期一

Predis is using Onion to build PEAR package.

Predis is using Onion

I'm glad to see this, nrk uses Onion to build their PEAR package.

predis commit: https://github.com/nrk/predis/commit/104cd1eae7f3fb2bff3ccd3193c3e31b8502af56

Use Onion to build PEAR packages of Predis.
Since Pearhub is currently broken (unfortunately the project does not seem to
be actively mantained anymore) but we still want to have PEAR packages for our
library, we need to automate the creation of a package.xml definition file to
build the actual packages that will be uploaded on a self-hosted PEAR channel.

Onion, while still in its alpha stage right now, works perfectly fine for our
needs and its own package.ini file looks simple enough to edit and maintain.

See http://c9s.github.com/Onion for more details about Onion and thank @c9s
for making it available.

2011年12月18日 星期日

PHPUnit_TestMore

PHPUnit_TestMore

PHPUnit is a great unit testing framework for PHP http://www.phpunit.de/manual/current/en/.

This helper library PHPUnit_TestMore https://github.com/c9s/PHPUnit_TestMore is for PHPUnit Test Framework, which brings the good things from the Test::More http://search.cpan.org/~mschwern/Test-Simple-0.98/lib/Test/More.pm library of Perl into PHP platform.

The original PHPUnit TestCase is trivial, for example:

function test() {
    $this->assertTrue( true );
    $this->assertArrayHasKey('foo', array('bar' => 'baz'));
    $this->assertClassHasAttribute('foo', 'stdClass');
    $this->assertContains(4, array(1, 2, 3));
}

If you write Perl, you must be familiar with this:

#!/usr/bin/env perl
use Test::More tests => 10;
$val = 1;
ok( $val );
is( 1, 1 );

Which is much simpler and easy, let you not to hate writing unit tests.

Then here is the PHP version's Test::More:

class FooTest extends PHPUnit_Framework_TestCase 
{
    function test() 
  {
        ok(1);
        ok(true);
        ok('string');
        not_ok(false);
  }
}

Setup phpunit.xml configuration

Create a file named phpunit.xml, and set the attribute printerClass to PHPUnit_Util_Log_TAP:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
        backupGlobals="false"
        verbose="true"
        syntaxCheck="true"
        convertErrorsToExceptions="true"
        convertNoticesToExceptions="true"
        convertWarningsToExceptions="true"
        printerClass="PHPUnit_Util_Log_TAP">
<testsuites>
    <testsuite name="PHPUnit">
    <directory suffix="Test.php">tests</directory>
    </testsuite>
</testsuites>
</phpunit>

In your bootstrap.php, require the TestMore helper.

require 'tests/PHPUnit_TestMore.php';

How it works

To reduce unit testing code, there is a function called debug_backtrace, which returns a call stack of current function call.

Here is some ideal PHP code synopsis for testing:

function test()
{
    ok( 1 );
    is( 1, 1);
}

To let the ok function get the caller object, we use debug_backtrace to call the original assertNotEmpty method:

function ok( $v , $msg = null )
{
    $stacks = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT );                      $testobj = $stacks[1]['object'];
    $testobj->assertTrue( $v ? true : false , $msg );
}

2011年12月1日 星期四

PHP - Current Onion PHP Package builder

Current Onion PHP Package builder (building #PEAR package) #PHP https://github.com/c9s/Onion



It works perfectly.

package.ini

The package config file is pretty simple, here:

And we used to write trivial xml format config by hands like this:

The package.xml 2.0


https://gist.github.com/1415004

2011年11月28日 星期一

PHP - GetOptionKit

The PHP built-in getopt function implements a very very simple option parser, it can not detect invalid options, invalid types, conflict options and can't parse options between arguments.

GetOptionKit is here to support more features, formats, detections and type constraints.
GitHub: https://github.com/c9s/GetOptionKit


GetOptionKit

A powerful GetOpt toolkit for PHP, which supports type constraints, flag, multiple flag, multiple values, required value checking.
GetOptionKit is based on PHP5.3, object-oriented, flexible and extendable, with fine unit testings with PHPUnit testing framework.
GetOptionKit also provides a printer class for printing well-layouted options.

Option SPEC

v|verbose   flag option (with boolean value true)
d|dir:      option require a value (MUST require)
d|dir+      option with multiple values.
d|dir?      option with optional value
dir=s       option with type constraint of string
dir=string  option with type constraint of string
dir=i       option with type constraint of integer
dir=integer option with type constraint of integer
d           single character only option
dir         long option name

Supported formats

program.php -a -b -c
program.php -abc
program.php -a -bc
with multiple values
program.php -a foo -b bar -c zoo
specify value with equal sign:
program.php -a=foo
program.php --long=foo

Synopsis

use GetOptionKit\GetOptionKit;

$getopt = new GetOptionKit;
$spec = $getopt->add( 'f|foo:' , 'option require value' );  # returns spec object.

$getopt->add( 'b|bar+' , 'option with multiple value' );
$getopt->add( 'z|zoo?' , 'option with optional value' );

$getopt->add( 'f|foo:=i' , 'option require value, with integer type' );
$getopt->add( 'f|foo:=s' , 'option require value, with string type' );

$getopt->add( 'v|verbose' , 'verbose flag' );
$getopt->add( 'd|debug'   , 'debug flag' );

$result = $opt->parse( array( 'program' , '-f' , 'foo value' , '-v' , '-d' ) );

$result = $opt->parse( $argv );

$spec = $result->verbose;
$spec = $result->debug;
$spec->value;  # get value

2011年11月27日 星期日

如何架設 PEAR Channel Server 來散佈你的 PHP 套件

架設 PEAR Channel Server 一直都不是特別容易的事情,尤其是 PEAR1 不夠成熟, PEAR2 提供的 SimpleChannelServer 筆者至今也無法順利使用(不斷的出現 Error )。

目前筆者試用下來,覺得 Fabien 寫的這套 Pirum Channel Server 算是最容易、最快速能佈署好的 PEAR Channel Server 。

安裝 Pirum

首先得將 Channel Server 加到你自己的設定中,才能從該 PEAR Channel 安裝 Pirum 套件。

$ pear channel-discover pear.pirum-project.org 
$ pear install pirum/Pirum

接著執行:

pirum

確定腳本已經正確安裝執行。

設置 Channel Server

再來,建立你的 Channel Server 目錄,假設為 ~/pear 好了

$ mkdir ~/pear

接著在 ~/pear 內建置 XML 檔 (當然是用手修改):

<?xml version="1.0" encoding="UTF-8" ?>
<server>
    <name>pear.pirum-project.org</name>
    <summary>Pirum PEAR channel</summary>
    <alias>pirum</alias>
    <url>http://pear.pirum-project.org/</url>
</server>

其中 name 為你的 channel server 名稱,url 為你的 channel server URL。 接著執行 pirum build 即可建置 pear channel server 的 XML 了:

$ pirum build ~/pear

新增 Apache site config

新增你的 Apache Site config 指定到 ~/pear 的這個目錄

<VirtualHost *:80>
    ServerName pear.dev
    RewriteEngine On
    RewriteOptions Inherit
    DocumentRoot "/Users/c9s/pear"
</VirtualHost>

使用瀏覽器瀏覽該位址就可以看到結果了。

App::gh 0.55


- Added a --long option to the search command of App::gh, and improved the search result printing.
- @mattn++ added a pullreq command, so you can send pull requests from command-line
- mattn also added an issue command, you can manage issues from command-line mostly.
- I've improved the issue printing and pull request printing.
- Thanks to  alexchorny, chocolate.  garu, gfx, tokuhirom, tyru, xaicron, zakame (ordered by alphabet)
- The "All" command is also improved, when running "gh all" on existing repositories, gh will execute `remote update --prune` command to update the repository.

Also thanks to those who contributed patches and improvements, the list below is grepped from the commit log of App::gh:

   8 Author: Alexandr Ciornii <alexchorny@gmail.com>
   5 Author: Breno G. de Oliveira <garu@cpan.org>
   1 Author: Chris Weyl <cweyl@alumni.drew.edu>
   9 Author: Cornelius <cornelius.howl@gmail.com>
   8 Author: Fuji, Goro <gfuji@cpan.org>
  36 Author: Ryan C. Thompson <rct@thompsonclan.org>
   4 Author: Tokuhiro Matsuno <tokuhirom@gmail.com>
   1 Author: Zak B. Elep <zakame@zakame.net>
 346 Author: c9s <cornelius.howl@gmail.com>
   4 Author: chocolateboy <chocolate@cpan.org>
   9 Author: mattn <mattn.jp@gmail.com>
   5 Author: tokuhirom <tokuhirom@gmail.com>
  30 Author: tyru <tyru.exe@gmail.com>
   1 Author: xaicron <xaicron@gmail.com>
   3 Author: yj <liyuray@gmail.com>

App::gh is on GitHub!
https://github.com/c9s/App-gh

2011年11月23日 星期三

CPAN 模組與 Debian 套件

在 Debian 的系統中,若 CPAN 模組與 Debian Repository 內的 CPAN 模組交互使用,很容易引起版本相依性衝突的問題,很可能會導致 Debian Apt 無法使用。

但是有時候為了特定環境部屬方便,還是會希望能夠將 CPAN 模組打包成 Debian Package。

* Solution:  dh-make-perl

先安裝 dh-make-perl 套件:

apt-get install dh-make-perl

dh-make-perl make --core-ok --build --recursive --requiredeps --cpan Plack

因此能打包出 Plack 的 deb 檔案。

要注意的是,套件若遇到 build_requires 無法滿足的狀況,程序就會被終止。

所以在 make 時,建議使用 --install 參數取代 --build 參數,或先安裝該模組以及該模組所有的相依模組。

若都無法建置,就還是得把 tarball 抓下來解開,重新 dh-make-perl 一次

dh-make-perl make --core-ok --build --recursive --requiredeps

以上。



* Solution: debian.pkgs.cpan.org

debian.pkgs.cpan.org 一個專門打包最新的 CPAN 模組的 Apt Repository,不過看了一下最後更新是 2008 年 (URL),所以還是別用吧!


CPAN::Packager

也是一個可將 CPAN 模組打包成 RPM, DEB 的工具,請看 dann 的 slide:



(抱怨: Blogger 還是沒辦法在 Rich Editor 裡自動幫我把 > < Escape 掉,等了好幾年,爛暴了)

2011年11月22日 星期二

關於 CPAN Dependency Tracking 模組相依性

由於專案需求,需要一些 Dependency Tracking 的東西來做點事情,以下是大概 survey 的結果:


* Carton,  Tatsuhiko Miyagawa 最近釋出的 Dependency 管理工具,也就是 Bundler,這主要是給模組開發者使用的工具。

開發者可以利用 Makefile.PL 準確的將相依的模組選擇正確的版本安裝,也可以將相依的模組依照正確的版本整捆打包起來。

在部屬的時候,可以直接使用這些模組安裝檔。



* CPAN::Dependency, 該模組使用 CPANPLUS 提供的後端 CPANPLUS::Backend 來剖析模組,可透過多種格式的 Dist Path 來取得 Distribution Object ,而 Distribution 又提供了 fetch, extract 等方法可以下載 Distribution 並且剖析該模組的相依性。

不過 CPAN::Dependency 似乎只能剖析一層的 Dependency ,無法 Recursive 剖析相依的子模組,所以得透過 process 選項來處理 CPAN 上所有的模組的資訊才有辦法取得樹狀結果。

但要跑完整個 Module List 也太久了,CPAN 上有超過十萬個 Module ,兩萬三千多個 Distribution。

不過一個很不錯的地方是,CPAN::Dependency 提供了 load_deps_tree 以及 save_deps_tree 的方法,所以可以儲存樹狀結果為 YAML 檔案,也可以再次載入回來。

至於 cpants DB 的後端支援則是壞掉了。



* Module::Dependency (2006 年),提供了一些腳本可以處理相依性的資訊:

執行 pmd_indexer.plx 可以索引某個目錄來取得所有的相依性資訊:

    $ pmd_indexer.plx -o ./unified.dat -t -b ~/src/perl/test/CPANTS-Weight-0.15

使用 pmd_dump.pl 則可以將資料 dump 出來:

    $ pmd_dump.pl -o ./unified.dat -A

pmd_grapher 則提供 graph 產生:


其他詳細範例可參考: http://cpansearch.perl.org/src/TIMB/Module-Dependency-1.86/examples/example.html



* Graph::Dependency (2006) 也是取得 dist tarball 之後 extract 取得 meta yaml 來產生 graph .. 不過已經壞掉了。



* CPAN::FindDependencies 的 API 看起來還不錯,不過使用 synopsis 提供的 Code 卻會 dump 出一堆亂碼 (????) 後來發現需要給 02packages 的 option 給 findeps 使用才行。

另外也沒有提供 debug, verbose 等選項,所以只能靜靜的等輸出結果。

修改後 (gist) 的輸出結果很理想,但是 perl 的 Core module 沒有過濾掉

其他部分都很 OK。


* CPANDB

CPANDB 使用了 ORLite 的 SQLite ORM 作為基底,提供了一個 SQLite 的 database ,利用 scripts/cpangraph 可繪製 CPAN Module 的關聯圖 (via GraphViz)。

SQLite 資料庫上基本上由遠端存取

GET http://svn.ali.as/db/cpandb.bz2 ==> 200 OK (16s)

再利用 ORLite::Mirror 來做遠端以及本地端的資料同步。

不過好像第二次存取 svn.ali.as 的時候就出現 301 Not Modified ...

又,為何使用了 scripts/cpangraph 後的 CPAN Graph 只有:



* Debian::Dependency 則可指出與 Debian 套件之間的相關性


* Devel::ModInfo (2002) 似乎太舊了,壞掉了。


* PAR 的 scandeps.pl ,能幫上一點忙,不過格式的部份好像無法匯出 YAML ?


* Leon Brocard 寫的 Module::CPANTS ,測試了一下覺得效果還 OK ,結果發現這個模組是測試
資料序列化之後,儲存成一個 Module ,最後更新時間為 2003 年,所有序列化的資料還是太舊了,放棄。


* Module::CPANTS::Analyse 則可以透過一個路徑解開一個 Distribution 之後取得大量的測試的 Meta Data,包含 meta_yml, kawalitee, file hashes, size 等等...


* CPANTS::Weight 則因為版本問題,需要 ORDB::CPANTS 0.05 版本,但只取得到 0.04 版本,所以無法運行。
ORDB::CPANTS version 0.05 required--this is only version 0.04 at /Users/c9s/perl5/perlbrew/perls/perl-5.14.2/lib/site_perl/5.14.2/CPANTS/Weight.pm line 33.
有誰可以告訴我 ORDB::CPANTS 0.05 版在哪?XDDDD





這篇大概就是純粹做個筆記

台灣寫 Perl 的人太少了,少到我覺得這篇整理實在價值不高。

墮落中 XD

2011年11月21日 星期一

PHP - isset 以及 array_key_exists 之比較


c9s
@bencrox @gslin 如果這種銜接 extension 的函數如 isset() 多用一層 pure php function 包起來,速度會變得比 array_key_exists 更慢 #damnItsTrue
11/11/21 下午3:14

c9s
@bencrox @gslin array_key_exists() 比 isset() 慢上 4.33 倍,會多上好幾個 cpu cycle,此外用 @ 符號,則是慢上 4 倍,建議能直接用 isset() 就用 isset()
11/11/21 下午3:12
gslin
都忘記有 isset() 了,用 array_key_exists() 用習慣了... http://t.co/w4w9UxWS
11/11/21 下午1:37

PHP - SplClassLoader

由於 Pure PHP 的 Class Loader 效能實在太差,現在的 PHP Team 於 wiki 上寫了關於 SplClassLoader 的 RFC ,使用 C 來實作 ClassLoader 提高效能。

不過目前仍在試驗階段 (Experimental)

2011年11月20日 星期日

Onion - 快速製作 PEAR 相容套件的途徑 A Fast Approach to make PEAR-compatible package.

為了解決 PEAR 套件包裝的問題,今天花了一點時間實作了 PHP CLIFramework 以及一個 PHP 套件管理程式 - Onion,可透過簡易的 INI 設定檔,快速建置 PEAR2 相容的套件規格檔,讓原本需要手動建置 500 多行 XML 減少到可以 6 行內的設定檔來建置套件,如下:



使用 Onion 可幫助開發者快速打包、散佈 PHP 套件,在系統間快速佈署套件。



設定檔格式

選擇 INI 格式設定檔的主要原因,就是因為易讀、易寫,且 PHP 從較早的版本就支援了 parse_ini_file 函式,所以稍微犧牲了資料結構的表現,選擇了 INI 格式作為套件規格檔的格式。

YAML 雖然提供了很好的多重資料結構表現格式,但是由於使用 YAML 格式將會使得很多使用者受到空白鍵、Tab 鍵的困擾,再者,YAML Parser 並不內建於 PHP ,目前的 Extension 也都不太穩定,若使用純 PHP 的 YAML Parser 則會增加相依性,所以目前不提供 YAML 格式的設定檔支援。

至於 Composer 使用了 JSON 格式,不熟 JavaScript 或者對於修改設定而言,方括號以及大括號都太不方便,所以不考慮 JSON 格式的設定檔,至於要易於資料流通,倒是可以考慮自動產生出 JSON 格式的超規格檔 (Meta File)。


目前功能

- 可透過設定檔產生 PEAR 相容規格的基本作者資訊、套件資訊、PEAR Channel 相關資訊、PHP 版本相依性、Extension 相依性等等資料。


目前狀態


- 1.9.4 版本的 PEAR Installer 於 PHP 5.3.8 版本運作良好。



需求

* PHP 5.3.8
* PEAR 1.9.4
* SimpleXml Extension


初期目標,是建立一個能夠產生 PEAR 相容的套件規格檔,可透過 PEAR 打包成 PEAR 套件,讓既有的套件可以使用目前的 PEAR Ecosystem (我不太確定現在 PEAR 這個狀態是否為 Ecosystem?)

長期目標,是希望能夠建立一個獨立運作的套件安裝、建置程式,可簡易建置套件、安裝套件、處理相依性、Bundles、Phar 包裝支援,整合版本控制資源等功能。






PHP PEAR package.xml 2.0 規格書

PEAR2 的 Pyrus 定義了 package.xml 2.0 規格書
http://pear.php.net/manual/en/guide.developers.package2.php

同時可透過 PEAR_PackageFileManager2 套件來將舊的 package.xml 1.x 版本轉為 2.0 版本的 package.xml 。

此外 package.xml 1.0 以及 1.3.6 已經 deprecated 了。http://pear.php.net/news/package.xml.1.0.php

不過 PEAR_PackageFileManager2 的執行結果真是慘不忍睹。

PHP 的 PEAR 生態圈問題



PHP 的 PEAR 生態圈有很多很嚴重的問題




1. 預設的 package 都是 alpha version ,沒人敢用,沒人敢用就得自己重寫

2. 就算重寫了,PEAR 套件的規格檔也是相當麻煩攏長的 XML,PEAR 也沒有提供好用的工具讓你建制 XML 規格檔 ,能跨過門檻的人就更少了,於是最後形成一種馬太效應,更沒有人願意釋出套件。

3. 釋出套件得先提 Proposal ,官方人員認可了才可允許套件上傳。

4. 使用 PEAR 下載的套件並不會預設執行測試(可能也沒有測試),所以套件作者可能都不知道有問題。

5. PEAR 回報 Issue 相當麻煩。

6. 無法評估每個套件的狀態,版本相容程度。

雖然寫 PHP 的人很多,但是能夠釋出的共用套件卻相當少,大多都相依於 Framework 或是大型 CMS。而目前能夠釋出 PEAR Package 的大多都是大公司,每個大公司幾乎都是各自為政的狀態,自己建自己的 PEAR Channel ,自己的文件瀏覽服務,每個做的都比 PEAR 官方的好。

但又因為 PHP PEAR 官方並不是很開放,PHP 版本功能差異很多,這讓很多套件無法達到向後相容 (backward-compatible) ,而這些 PHP 公司也無法貢獻回原有的社群,只能另起爐灶。 (如 packagist, pear2, pearfarm .. 等等)

要解決這個問題,得先定義好一個夠彈性、簡易的 Meta File 規格,能夠產生一個向後相容的 PEAR package.xml 規格檔,讓套件包裝簡化(同時也得相容 Pyrus 才行)。

接著建立一個新的服務,使用不同版本的 PHP 建立測試檔,讓每個套件的穩定、相容程度都能輕易辨識,再慢慢的再把舊有的東西 (舊時代 Java 狂的遺毒) 逐漸汰換掉 ....

(這個大概是 Perl 社群幾十年前在做的事情吧? XD

詳見:
http://www.brainbell.com/tutors/Perl/CPAN_History.htm

2011年11月19日 星期六

PHP Reflection Class

PHP 從 5.3 開始,支援了 Reflection 的功能,而這個 Reflection 基本上是從 Java 的 Reflection API 而來。( 基本上 PHP 什麼都想抄 Java )

透過 Reflection API ,可以在執行期間取得該 Object method 的檔案名稱、方法參數、名稱、屬性、類別名稱、父類別、介面等,而不需要透過骯髒的方式來剖析 PHP 程式碼。

這方面只能取得物件的基本資訊,沒有辦法在執行時期去對物件的類別或超類別做修改。

而雖然也有人實作了 RunKit extension 來實現執行期間的物件、函數修改, 但也未包含在 PHP Core Extension 內,有相當久的時間沒有維護更新 (最後一次是 2006 年),很多功能也都是 Experimental,而且要透過 PECL 來編譯 PHP5.3 的 RunKit 是無法的,直接爛掉。

而另外一個 ClassKit extension 也是胎死腹中。

結論

PHP 爛到爆

2011年11月15日 星期二

webgrind & GrindKit

webgrind 是一個可讀取 PHP Xdebug extension 所產生出來的 cachegrind 檔案格式的一個 Profiler ,基於網頁端,可跨平台,該專案使用 PHP 簡易的剖析了 cachegrind 的基本資訊,計算出 summary cost , inclusive cost, caller, callee 等資訊,並定義了一個新的格式用以儲存計算後的資料。

但由於 webgrind 的 GitHub Repository 沒有分 develop, master branch ,我甚至不知道哪個才是穩定版本的 webgrind ,此外也無 Unit Testing,基於專案需求,我因此實作了一個 cachegrind 的剖析器命名為 GrindKit,採用 PHP5.3 的 Namespace 以及 OO ,已於 GitHub 上釋出,著重於 cachegrind 檔案的剖析與測試。

https://github.com/c9s/GrindKit

2011年11月1日 星期二

Web Scrapers

要談 Web Scraper ,PHP 好不容易趕上了某個 Check Point

Goutte 是 @fabpot 寫的一個 PHP Web Scraper ,基本上 API 與 Perl 的 WWW::Mechanize 類似,不過 Perl 的 WWW::Mechanize 卻是相當古老的東西了。

Ruby 的這個部分也是直接使用 WWW::Mechanize 的這個名稱: http://www.johnyerhot.com/2008/05/19/anatomy-of-a-ruby-web-scraper/

若查看 WWW::Mechanize 的 ChangeLog ,最早可追溯至 2002 年的 0.30 版本,而 LWP::UserAgent 更是可追溯到 1995 年。

再來提供 DSL 來撰寫 Scraper 的模組,是 miyagawa 所寫的 Web::Scraper ,ChangeLog 最早可追溯至 2007 年,而 Web::Scraper 基本上靈感來自於 Ruby 的 Scrapi ,可使用 DSL 來撰寫 Scrapper ,該 Ruby 模組最早也可追溯至 2006 年。

接著 2007 年中 phpQuery 計畫開始,2008 年,Ingy 寫了 pQuery ( porting jQuery to Perl )

而 PHP 比較成熟的 Web Scraper ,則是在最近幾年: Symfony2 內有一個 Crawler Class ( http://symfony2.openthinklabs.com/home/dokumentasi-symfony2/panduan/testing/crawler )

以及 Fabien Potencier 的 Goutte ( https://github.com/fabpot/Goutte )

一些 PHP 最近的發展

PEAR 已經太過老舊,因此現在有了一個 PEAR2 ,第二個版本的 PEAR ( http://pear2.php.net )。

Client 端可以使用 Pyrus 這個新的 Client 來取代原本的 PEAR ,該 Pyrus 採用 PHP5.3 所附加的 Phar 技術,類似 Java 的 Jar ,可將 source code 打包於單一個檔案。

此外,由於 PEAR 的包裝描述檔案,基本上都採用 XML 的格式 (package.xml) ,Symfony 的一些相關人士寫了一個新的 Package Service ( http://packagist.org/ ) 以及一個 Packager - Composer ( http://getcomposer.org )。

Composer 本身也使用 Phar 技術打包。基本上 Composer 套件格式採用 JSON ,也可透過 Composer 做 Local site 的安裝。

如下列指令:

$ php composer.phar install


附帶一提,打包 Phar 檔,也必須將您的 Autoloader 寫進去才行。 PHP 於 2009 年時初次釋出 5.3 版之後終於有了 namespace,所以可使用 autoloader 來自動將 namespace\class 載入。

有了 Namespace 之後,現在大部分套件都將 namespace 分隔字符換為 DIRECTORY_SEPARATOR ,來載入 Class , 但是所有舊有的 PEAR 套件採用的載入路徑規則卻是另一個樣,所以,如今寫 PHP Class Autoloader 也得另外寫一套 PEAR Style Compatible 的 Class Autoloader 才行。

結論: 

PHP 落後別人好幾年呀!

Zend VM Source

本來打算來看 Zend Engine (Zend VM) 的 Document ,沒想到 php-src 內的 RFC 還停留在 2001 年。

上了 php wiki 找了一下,好不容易有一篇解說 zend object ( https://wiki.php.net/internals/engine/objects 以及 https://wiki.php.net/internals/engine ) 。千萬不要去看 php-src 內的 OBJECT2 呀,大概是好幾千年前的東西了,可見 Zend Team 連 source code repository 內舊的東西都懶得整理呀。

另外 php-doc 內最近多了一個 section:  PHP at the Core: A Hacker's Guide to the Zend Engine ,不過 Zend Engine 2 API 也是空的,勉強還有一個 opcode list http://tw.php.net/manual/en/internals2.opcodes.ops.php 。

隔壁章節則是 Zend Engine 1.0  http://tw.php.net/manual/en/internals2.ze1.zendapi.php,可能對搞懂 Zend VM 會有點幫助,不過 Zend Engine 1.0 與 2.0 差異多少則不得而知,PHP 5.4 對於 VM 也有相當大的改動。 總之,很多 section 內都是空的 (大概是 docbook 格式的文件相當難寫,沒人想寫吧!)

此外 OpCode 方面可使用 vld extension dump 出來 http://pecl.php.net/package/vld 。

另外對 bytecode to LLVM Bitcode Wiki 上也有一些基本的描述: https://wiki.php.net/ideas/bytecodetollvm ,目前的 LLVM generator 可以通過一點基礎的測試,但是還得大量整理來追上 LLVM 的版本,也可參考一下 VMKit ( http://vmkit.llvm.org/ )


最近 Zend 那群人打算把 svn 搬移到其他 DVCS 上,目前 php source code 可在 GitHub 上找到: https://github.com/php/php-src


本來也打算上 #php IRC channel ,結果沒想到該頻道必須被邀請才能加入的私人頻道。



總之,PHP Internal 相關的東西,比起其他社群,看起來並不是很活躍,希望 FaceBook 可以促進一些刺激之類的。

2011年10月26日 星期三

Hacking Plan

Projects to survey:

* RoadSend
* HipHop
* php-llvm   (seems dead)

Sections

* Zend API
* Zend VM
* Zend AST, OpCode
* LLVM IR
* LLVM BitCode Generation
* Zend Extension
* Perl XS Extension

2011年9月6日 星期二

使用 Dancer 快速建置一個 Web Application

使用 Dancer 可以使用簡潔的語法快速建構一個 Website.

安裝 Dancer:

$ cpanm Dancer

$ dancer -a WebApp

便會產生 WebApp 的 Structure。

一個基本的 post route:


post '/' => sub {
    return "Hello world";
}

含有名稱的 route:


get '/hello/:name' => sub {
    return "Hi there " . params->{name};
};

其他 Dancer Export 的 Helper functions 
可參考 https://metacpan.org/module/Dancer

預設樣板引擎是 Template Toolkit 。



$ perl bin/app.pl

即可啟動 Server 。


相關文件參考:

Quick Start
Dancer::Cookbook