If you attempt to throw an exception from a PHP destructor or an PHP exception handler, your script will execute fine for the most part and then crash with the rather cryptic error message, “Fatal error: Exception thrown without a stack frame in Unknown on line 0“. This message is unfortunately very cryptic if you are trying to debug your code. This effect is further amplified due to a lack of PHP debuggers and you must instead resort to using various print_r()s and var_dump()s in order to debug the program. The error message in basic form means that you’ve thrown an exception where an exception cannot be thrown (leading to “no stack frame” – exception handlers and destructors do not have a stack frame. This instead results in this rather cryptic error message that does not include script locations or detailed error information).
Most often, the error will appear if you use an exception handler combined with an error reporting to exception handler by converting it to an ErrorException, then there a suddenly a whole new magnitude of ways to throw errors within the exception handle, especially if E_NOTICE, E_STRICT and/or E_WARNING errors are converted. This form most often occurs when you use variables without first initializing them. This error may be preventable by wrapping the exception handler within a try/catch block.
A second form of this error occurs when you attempt to throw an exception in a destructor. This is well documented in the PHP manual, but this can still be triggered if you accidentally throw an exception:
Manually – calling “throw new Exception(‘hello world’)’ in a destructor
Implicitly – calling a function that throws an exception (e.g. calling function foo() which throws an exception)
Error handler (ErrorException) – instating a user-defined function as an error handler which throws an ErrorException (which is still an error)
There is no exactly solid way to identify this type of error as you may not know exactly what your functions do. If you are throwing exceptions manually in your destructor, you need to go back to the PHP manually and read that it is not possible to throw exceptions within the destructor (as it lacks a stack frame). For the other two, you may need to comment out your destructors and manually uncomment parts until you reach the point where you find the error line as the error message produced by PHP is not too informative.
If you found this article helpful or interesting, please help Compdigitec spread the word. Don’t forget to subscribe to Compdigitec Labs for more useful and interesting articles!
摘自:http://www.compdigitec.com/labs/2009/08/02/solving-fatal-error-exception-thrown-without-a-stack-frame-in-unknown-on-line-0/
2010年10月31日 星期日
2010年10月27日 星期三
DIV圖層 被 Flash 覆蓋解決方式
ok,這篇單純是因為google下的關鍵字第一篇找不到能夠直接用的,就找自己已經完成可用的方式做個紀錄。
前面幾篇過於冗長,不必要的資料太多了..
基於有點批評,就不說我下了什麼關鍵字了。 (或許是關鍵字下的太精簡?)
照例一行關鍵字:DIV、CSS、z-index、flash、swf、圖層、覆蓋、被蓋住、遮住、absolute
相信網頁設計者會碰到使用flash時,將原本在其上的圖層蓋住,而這篇文章就是講解如何將其恢復到正常的圖層位置。
通常在越上方的圖層會將下方的圖層蓋住。
例如:
正常情況下top圖層若使用 position:absolute; ,則在相同位置時,top的資料會蓋住下方的banner圖層。
但flash通常都會浮在最上方,跳脫了原本的層次,所以下面將講解如何處理。
處理方式為將置入的object(物件)標籤 embed加入個參數 wmode="transparent" 即可。
保險的話在加入 ,並在css上方div圖層加入z-index:10,而下方div則加入z-index:1。
看不懂對不對? 沒錯,google第一頁的就是這樣,不清不楚的。
下面例子:(使用meebo的meebo me做示範)
環境解釋:top圖層放圖片、banner圖層放flash檔。
原始:
增加部份:(使用粗體橘字)
------------手工分隔線-------------
簡單來說只需要在 object 標籤內加入
並在embed標籤內,認src參數,在其加入 wmode="transparent" 即可。
而加入後也會有flash背景透明的效果。
css部份的話,可以用此方式:(也是用上方的top跟banner例子來舉例。)
連結/匯入方式
#top {
position:absolute;
z-index:10;
}
#banner{
position:absolute;
z-index:1;
}
z-index上只要數字越大,圖層將會在越上面。下方的圖層則會被上方的遮住(若為同一位置的話)。
HTML內方式
前面幾篇過於冗長,不必要的資料太多了..
基於有點批評,就不說我下了什麼關鍵字了。 (或許是關鍵字下的太精簡?)
照例一行關鍵字:DIV、CSS、z-index、flash、swf、圖層、覆蓋、被蓋住、遮住、absolute
相信網頁設計者會碰到使用flash時,將原本在其上的圖層蓋住,而這篇文章就是講解如何將其恢復到正常的圖層位置。
通常在越上方的圖層會將下方的圖層蓋住。
例如:
我是上方圖層
我是banner圖層
正常情況下top圖層若使用 position:absolute; ,則在相同位置時,top的資料會蓋住下方的banner圖層。
但flash通常都會浮在最上方,跳脫了原本的層次,所以下面將講解如何處理。
處理方式為將置入的object(物件)標籤 embed加入個參數 wmode="transparent" 即可。
保險的話在加入 ,並在css上方div圖層加入z-index:10,而下方div則加入z-index:1。
看不懂對不對? 沒錯,google第一頁的就是這樣,不清不楚的。
下面例子:(使用meebo的meebo me做示範)
環境解釋:top圖層放圖片、banner圖層放flash檔。
原始:
增加部份:(使用粗體橘字)
------------手工分隔線-------------
簡單來說只需要在 object 標籤內加入
並在embed標籤內,認src參數,在其加入 wmode="transparent" 即可。
而加入後也會有flash背景透明的效果。
css部份的話,可以用此方式:(也是用上方的top跟banner例子來舉例。)
連結/匯入方式
#top {
position:absolute;
z-index:10;
}
#banner{
position:absolute;
z-index:1;
}
z-index上只要數字越大,圖層將會在越上面。下方的圖層則會被上方的遮住(若為同一位置的話)。
HTML內方式
.... 後面省略
------------------------------------
後記:
因為meebo me widget的標題不能使用中文,本來打算使用gif檔用圖層方式覆蓋,但若使用了 wmode="transparent" ,則無法輸入中文,所以只能作罷。
以上
因為google第一頁沒辦法直接處理所以發文 XD
reference: http://ezcshi.pixnet.net/blog/post/25515486
------------------------------------
後記:
因為meebo me widget的標題不能使用中文,本來打算使用gif檔用圖層方式覆蓋,但若使用了 wmode="transparent" ,則無法輸入中文,所以只能作罷。
以上
因為google第一頁沒辦法直接處理所以發文 XD
reference: http://ezcshi.pixnet.net/blog/post/25515486
2010年10月26日 星期二
PHP code coverage implement
Step1:
Install XDebug
http://xdebug.org/find-binary.php
Step2:
build.xml in CruiseControl
摘自:http://pessoal.org/blog/category/php/
Install XDebug
http://xdebug.org/find-binary.php
Step2:
build.xml in CruiseControl
摘自:http://pessoal.org/blog/category/php/
2010年10月25日 星期一
2010年10月24日 星期日
PHP: Traversing directories only
foreach(glob('startDirectory/*', GLOB_ONLYDIR) as $myFilename)
{
echo 'Filename: ' . $myFilename . '
';
}
SQLite Primary Key column not auto incrementing
When developing with PHP, I frequently use SQLite databases since they’re very disposable and keeps from cluttering my MySQL server with a bunch of development/testing databases that may be abandoned or no longer used.
One of the problems I’ve had is when dealing with the Primary Key column and discovering that it for some reason won’t auto increment like it should.
So I did some testing and troubleshooting and finally figured it out.
Here’s a few “guidelines” that may help you out so you can avoid these issues too.
MY ENVIRONMENT:
I am using PHP 5.3.2 and PDO.
PDO is available with PHP as of PHP 5.1, but Sqlite3 is available as of PHP 5.3.0 which you can read more about at http://us.php.net/manual/en/book.sqlite3.php.
INTEGER not INT
Very often when writing PHP scripts, the option to choose between MySQL or SQLite database types comes into play. Also, many of us learn how to use a database with PHP using MySQL first and SQLite is a little different regarding the acceptable SQL syntax. MySQL will gladly accept INT as a substitution for INTEGER and SQLite won’t complain either, but in my experiences SQLite doesn’t see the two as being the same for some reason.
Take a look at this example: (You can try it yourself if you like)
$sql = "CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(50) DEFAULT NULL )";
This will create the table without any errors, but when you insert a new row, the id column won’t increment and will simply be empty. You can add NOT NULL to it, but it still doesn’t make any difference.
The other thing I noticed was that it wasn’t bias towards using an empty string value for this field when the data type was set to INT as in this example:
$sql = "INSERT INTO test_table (id, name) VALUES ('', 'JohnDoe')";
Now try it again and add AUTOINCREMENT to it like this:
$sql = "CREATE TABLE test_table (
id INT PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) DEFAULT NULL )";
Now all of the sudden you should get an error (if you have the error attribute set) similar to this:
'SQLSTATE[HY000]: General error: 1 AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY'
So this clearly shows that INT and INTEGER are NOT the same.
As soon as you change INT to INTEGER in your SQL syntax, the primary key works just fine and it doesn’t matter if the AUTOINCREMENT is present or not.
Specifying Field Lengths Will Cause Problems
The only field data types SQLite requires (at least in PHP) a field length for is the ‘VARCHAR’ type. From my understanding, it doesn’t enforce this length, but I may be wrong. Either way, specifying data lengths to other field types normally won’t cause any sort of errors, but they will be ignored.
However, in the case of the PRIMARY KEY field, it seems to have the same effect as using INT instead of INTEGER, even if the data type you specify IS INTEGER.
Here’s an example:
$sql = "CREATE TABLE test_table (
id INTEGER(5) PRIMARY KEY,
name VARCHAR(50) DEFAULT NULL )";
Now if you insert a row, you will see that the id column isn’t incrementing.
If you add AUTOINCREMENT to the end, you will see the SQLite error message I mentioned above.
So be sure to leave off the data length from your SQL syntax for the primary key field.
That pretty much sums it up and hopefully helps you avoid the headaches I had before figuring this out.
Additional SQLite SQL syntax caveats
Something I see used often in SQL syntax for MySQL is the ( ` ) character as in this example:
$sql = "INSERT INTO test_table (`id`, `name`) VALUES ('', 'JohnDoe')";
They look a lot like apostrophes, but they’re actually what’s called spacing acute characters. On a U.S. Keyboard, it’s the key just above the TAB key.
They have no real purpose (that I know of) other than just making it “nicer” looking.
The problem comes when trying to use that syntax in SQLite queries.
SQLite doesn’t like these characters and it will result in an error. This also was a lesson that took me a lot of wasted time to figure out, so just avoid them to begin with.
摘自:http://mydumbthoughts.wordpress.com/2010/06/12/sqlite-primary-key-column-not-auto-incrementing/
One of the problems I’ve had is when dealing with the Primary Key column and discovering that it for some reason won’t auto increment like it should.
So I did some testing and troubleshooting and finally figured it out.
Here’s a few “guidelines” that may help you out so you can avoid these issues too.
MY ENVIRONMENT:
I am using PHP 5.3.2 and PDO.
PDO is available with PHP as of PHP 5.1, but Sqlite3 is available as of PHP 5.3.0 which you can read more about at http://us.php.net/manual/en/book.sqlite3.php.
INTEGER not INT
Very often when writing PHP scripts, the option to choose between MySQL or SQLite database types comes into play. Also, many of us learn how to use a database with PHP using MySQL first and SQLite is a little different regarding the acceptable SQL syntax. MySQL will gladly accept INT as a substitution for INTEGER and SQLite won’t complain either, but in my experiences SQLite doesn’t see the two as being the same for some reason.
Take a look at this example: (You can try it yourself if you like)
$sql = "CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(50) DEFAULT NULL )";
This will create the table without any errors, but when you insert a new row, the id column won’t increment and will simply be empty. You can add NOT NULL to it, but it still doesn’t make any difference.
The other thing I noticed was that it wasn’t bias towards using an empty string value for this field when the data type was set to INT as in this example:
$sql = "INSERT INTO test_table (id, name) VALUES ('', 'JohnDoe')";
Now try it again and add AUTOINCREMENT to it like this:
$sql = "CREATE TABLE test_table (
id INT PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) DEFAULT NULL )";
Now all of the sudden you should get an error (if you have the error attribute set) similar to this:
'SQLSTATE[HY000]: General error: 1 AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY'
So this clearly shows that INT and INTEGER are NOT the same.
As soon as you change INT to INTEGER in your SQL syntax, the primary key works just fine and it doesn’t matter if the AUTOINCREMENT is present or not.
Specifying Field Lengths Will Cause Problems
The only field data types SQLite requires (at least in PHP) a field length for is the ‘VARCHAR’ type. From my understanding, it doesn’t enforce this length, but I may be wrong. Either way, specifying data lengths to other field types normally won’t cause any sort of errors, but they will be ignored.
However, in the case of the PRIMARY KEY field, it seems to have the same effect as using INT instead of INTEGER, even if the data type you specify IS INTEGER.
Here’s an example:
$sql = "CREATE TABLE test_table (
id INTEGER(5) PRIMARY KEY,
name VARCHAR(50) DEFAULT NULL )";
Now if you insert a row, you will see that the id column isn’t incrementing.
If you add AUTOINCREMENT to the end, you will see the SQLite error message I mentioned above.
So be sure to leave off the data length from your SQL syntax for the primary key field.
That pretty much sums it up and hopefully helps you avoid the headaches I had before figuring this out.
Additional SQLite SQL syntax caveats
Something I see used often in SQL syntax for MySQL is the ( ` ) character as in this example:
$sql = "INSERT INTO test_table (`id`, `name`) VALUES ('', 'JohnDoe')";
They look a lot like apostrophes, but they’re actually what’s called spacing acute characters. On a U.S. Keyboard, it’s the key just above the TAB key.
They have no real purpose (that I know of) other than just making it “nicer” looking.
The problem comes when trying to use that syntax in SQLite queries.
SQLite doesn’t like these characters and it will result in an error. This also was a lesson that took me a lot of wasted time to figure out, so just avoid them to begin with.
摘自:http://mydumbthoughts.wordpress.com/2010/06/12/sqlite-primary-key-column-not-auto-incrementing/
2010年10月22日 星期五
SQLite介紹
(一) SQLite介紹
SQLite第一個Alpha版本誕生於2000年5月. 至今已經有4個年頭了. 而在今年的5月SQLite也迎來了一個新的里程: SQLite 3.
下面是你訪問SQLite官方網站: www.sqlite.org 時第一眼看到關於SQLite的特性.
1. ACID事務
2. 零配置 – 無需安裝和管理配置
3. 儲存在單一磁盤文件中的一個完整的數據庫
4. 數據庫文件可以在不同字節順序的機器間自由的共享
5. 支持數據庫大小至2TB
6. 足夠小, 大致3萬行C代碼, 250K
7. 比一些流行的數據庫在大部分普通數據庫操作要快
8. 簡單, 輕鬆的API
9. 包含TCL綁定, 同時通過Wrapper支持其他語言的綁定
10. 良好註釋的源代碼, 並且有著90%以上的測試覆蓋率
11. 獨立: 沒有額外依賴
12. Source完全的Open, 你可以用於任何用途, 包括出售它
從代碼架構圖你可以輕鬆的看出, 是的, SQLite非常簡單. 對, SQLite的設計思想就是簡單:
1. 簡單的管理
2. 簡單的操作
3. 簡單的在程序中使用它
4. 簡單的維護和客制化
因為簡單所以它快速, 但雖然簡單, 卻仍非常可靠. 適合SQLite的應用場所有, 網站,嵌入式設備和應用, 應用程序文件格式, 代替特別的文件, 內部或臨時數據庫, 命令行數據集分析工具, 在演示或測試中代替企業級數據庫, 數據庫教學, 試驗SQL語言擴展等. 但並不是所有都合適, 比如在使用Server/Client結構的時候,高負荷的網站,高並發等情況下並不建議使用SQLite.
本文重點在於介紹SQLite在PHP中的應用, PHP作為Web應用中一個重要力量一直在不斷的前進和發展. 在馬上就要Release的PHP的第五個版本中, 不再將MySQL作為默認支持, 而轉為將SQLite的擴展作為默認支持. 從某種程度上說MySQL的廣泛應用有PHP的很大功勞. 雖然說PHP改變默認支持有MySQL的授權改變的原因, 但選擇SQLite也是有原因的, 理由就在於上面所提到的那些特性. 其實MySQL從來就不是完全免費的, 你無法用於商業用途. 而SQLite是完全的open的.
(二) SQLite SQL
SQLite的SQL從很大程度上實現了ANSI SQL92標準. 特別的SQLite支持視圖, 觸發器, 事務, 支持嵌套SQL. 這些都會在下面應用的過程中講到, 故這邊先暫時放下, 而主要說說SQLite所不支持的一些SQL.
1. 不支持Exists, 雖然支持in(in是Exists的一種情況)
2. 不支持多數據庫, 如: create table db1.table1 as select * from db2.table1;
3. 不支持存儲過程
4. 不支持Alter View/Trigger/Table
5. 不支持Truncate, 在SQLite中Delete不帶Where字句時和Truncate的效果是一樣的.
6. 不支持Floor和Ceiling函數, 還有其他蠻多的函數
7. 沒有Auto Increment(自增)字段, 但是SQLite其實是支持Auto Increment的, 即在將該字段設置為」 INTEGER PRIMARY KEY」的時候.
8. 不支持If Exists
……
詳細的SQL支持可以訪問: http://www.sqlite.org/lang.htm
詳細的不支持SQL可以訪問: http://www.sqlite.org/cvstrac/wiki?p=UnsupportedSql
(三) SQLite的數據類型
首先你會接觸到一個讓你驚訝的名詞: Typelessness(無類型). 對! SQLite是無類型的. 這意味著你可以保存任何類型的數據到你所想要保存的任何表的任何列中, 無論這列聲明的數據類型是什麼(只有在一種情況下不是, 稍後解釋). 對於SQLite來說對字段不指定類型是完全有效的. 如:
Create Table ex1(a, b, c);
誠然SQLite允許忽略數據類型, 但是仍然建議在你的Create Table語句中指定數據類型. 因為數據類型對於你和其他的程序員交流, 或者你準備換掉你的數據庫引擎. SQLite支持常見的數據類型, 如:
CREATE TABLE ex2(
a VARCHAR(10),
b NVARCHAR(15),
c TEXT,
d INTEGER,
e FLOAT,
f BOOLEAN,
g CLOB,
h BLOB,
i TIMESTAMP,
j NUMERIC(10,5)
k VARYING CHARACTER (24),
l NATIONAL VARYING CHARACTER(16)
);
前面提到在某種情況下, SQLite的字段並不是無類型的. 即在字段類型為」Integer Primary Key」時.
(四) SQLite的Wrapper
由於SQLite有別於其他數據庫引擎的TCP/IP或RPC訪問方式, 完全地是本地的操作, 從某種角度來說你可以說SQLite和MS的Access很相似, 但是更小更強大. 所謂Wrapper即使對SQLite提供的接口進行封裝, 使其他語言可以訪問, 使用SQLite.
SQLite本身是提供C和Tcl的接口的. 所以可以非常輕易的和PHP相結合. 除了PHP的Wrapper以外, 還有許多世界各地的程序員提供了各種語言的SQLite的接口封裝, 如Python, C++, Java, .Net…… 所流行的語言基本都有.
(五) PHP的環境下使用SQLite
1. PHP下的安裝
在PHP5中, SQLite已作為默認支持的模塊.在PHP4中你需要進行安裝. 首先去http://pecl.php.net/package/SQLite 去下載到SQLite的擴展, 注意Windows下的版本需要去http://snaps.php.net/win32/PECL_STABLE/php_sqlite.dll 下載, 當然你也可以下載代碼自己編譯.事實上在linux下只需要使用命令: 『pear install sqlite』就可以完成安裝,而在Win下需要修改php.ini, 同樣的使PHP4支持SQLite.
此時你已經無需再安裝任何東西了, 而你也已經完全支持SQLite了, 一個簡單, 快速, 可靠的數據庫.
如果你需要一個管理軟件, 那麼你可以嘗試使用SQLiteManager (www.sqlitemanager.org), 一個與PHPMyAdmin類似的針對SQLite的數據庫管理系統.
該系統的界面大致如下:
2. 第一個使用SQLite的PHP程序.
我們創建一個叫binzy的數據庫, 並創建一個叫Binzy的Table, 有2個字段, 分別是ID, Title. 而其中ID為INTEGER PRIMARY KEY, 即自增三主鍵. 並在其中插入了2條數據」Binzy」, 「Jasmin」.
打開並顯示數據:
if ($db = sqlite_open('../binzy.db', 0666, $sqliteerror))
{ // 打開
SQLite$result = sqlite_query($db,'select * from Binzy'); // 查詢while($row = sqlite_fetch_array($result)) // 獲得結果
{
print 'ID=>'.$row['MyID'].', Name=>'.$row['Name'].'
';
}
} else {die ($sqliteerror);}
結果如下,
接下來Insert一條記錄, 其中我們會使用到SQLite的事務.
if ($db = sqlite_open('../binzy.db', 0666, $sqliteerror)) {
sqlite_query($db,'BEGIN TRANSACTION'); // 開始事務
if (@sqlite_query($db,'insert into Binzy (Name) values (\'Binzy&Jasmin\')'))
{
print 'Execute Successfully';
sqlite_query($db,'COMMIT TRANSACTION'); // 提交事務
}
else
{
print sqlite_error_string(sqlite_last_error($db));
sqlite_query($db,'ROLLBACK TRANSACTION'); // 回滾事務
}
} else {
die ($sqliteerror);
}
如果執行失敗, 便會出現這樣的畫面,
成功則是這樣的,
是的, 如果你已經熟悉使用PHP對MySQL之類的數據庫進行操作, 那麼SQLite幾乎是一樣的, 而且更為簡潔.
3. 使用Pear::DB (PHP4中)
上面的例子中我們是使用PHP的函數直接對SQLite進行訪問, 這樣的訪問方式是不推薦使用的. 更好的方式是使用某種數據訪問抽像層, 如Pear的DB. 下面是2中查詢例子的重寫. 使用某個數據訪問抽像層會更方便更安全, 並且可以在需要進行數據庫遷移的時候盡可能減小成本.
require_once('DB.php');
$dbh = DB::connect('sqlite://@localhost/../binzy.db?mode=0666'); // 打開
$dbh->setFetchMode(DB_FETCHMODE_ASSOC);
if (!DB::isError($dbh))
{
$result = $dbh->query('select * from Binzy'); // 查詢
if (!DB::isError($result))
{
while($row = $result->fetchRow()) // 讀取
{ print 'ID=>'.$row['MyID'].', Name=>'.$row['Name'].'
';
}
$dbh->disconnect();
}
else
{
print($dbh->message);
$dbh->disconnect();
}
}
else
{
print($dbh->message);
$dbh->disconnect();
}
4. 使用Creole (PHP5中)
Creole是由phpdb.org開發的面向PHP5的數據訪問抽像層. 關於Creole可參考本期中的《Creole :新興數據抽像層》.
Pear::DB並沒有針對PHP5進行改變, 只是因為PHP5對PHP4良好的兼容性, 使得Pear::DB在PHP5下仍能很好的工作. 所以在你使用PHP5的時候推薦使用Creole.
require_once('creole/Creole.php');
$Connection = null;
try{
$Connection = Creole::getConnection('sqlite://@localhost/../binzy.db?mode=0644'); // 獲得Connection
$rs = $Connection->executeQuery('select * from Binzy'); // Get ResultSet while($rs->next())
{
print 'ID=>'.$rs->getInt('myid').', Name=>'.$rs->getString('name').'
';
}
$Connection->close();
}
catch(SQLException $exception) // Catch Exception
{
$Connection->close();
print $exception->getMessage();
}
(六) 總結
隨著PHP5的即將到來, 給我們帶來了許多新的語言特性, 使PHP更加適合於構建強大健壯的各類系統. 而隨著PHP5一起走進PHP開發人員視線的SQLite則給我們帶來了有別於MySQL的驚喜. 是的, 他簡單卻又強大, 穩定. 而在剛剛過去的六月底新版本的SQLite3已經Release了第一個測試版本, 不僅僅帶來了新的文件結構, 也帶來了許多新的特性.
SQLite第一個Alpha版本誕生於2000年5月. 至今已經有4個年頭了. 而在今年的5月SQLite也迎來了一個新的里程: SQLite 3.
下面是你訪問SQLite官方網站: www.sqlite.org 時第一眼看到關於SQLite的特性.
1. ACID事務
2. 零配置 – 無需安裝和管理配置
3. 儲存在單一磁盤文件中的一個完整的數據庫
4. 數據庫文件可以在不同字節順序的機器間自由的共享
5. 支持數據庫大小至2TB
6. 足夠小, 大致3萬行C代碼, 250K
7. 比一些流行的數據庫在大部分普通數據庫操作要快
8. 簡單, 輕鬆的API
9. 包含TCL綁定, 同時通過Wrapper支持其他語言的綁定
10. 良好註釋的源代碼, 並且有著90%以上的測試覆蓋率
11. 獨立: 沒有額外依賴
12. Source完全的Open, 你可以用於任何用途, 包括出售它
從代碼架構圖你可以輕鬆的看出, 是的, SQLite非常簡單. 對, SQLite的設計思想就是簡單:
1. 簡單的管理
2. 簡單的操作
3. 簡單的在程序中使用它
4. 簡單的維護和客制化
因為簡單所以它快速, 但雖然簡單, 卻仍非常可靠. 適合SQLite的應用場所有, 網站,嵌入式設備和應用, 應用程序文件格式, 代替特別的文件, 內部或臨時數據庫, 命令行數據集分析工具, 在演示或測試中代替企業級數據庫, 數據庫教學, 試驗SQL語言擴展等. 但並不是所有都合適, 比如在使用Server/Client結構的時候,高負荷的網站,高並發等情況下並不建議使用SQLite.
本文重點在於介紹SQLite在PHP中的應用, PHP作為Web應用中一個重要力量一直在不斷的前進和發展. 在馬上就要Release的PHP的第五個版本中, 不再將MySQL作為默認支持, 而轉為將SQLite的擴展作為默認支持. 從某種程度上說MySQL的廣泛應用有PHP的很大功勞. 雖然說PHP改變默認支持有MySQL的授權改變的原因, 但選擇SQLite也是有原因的, 理由就在於上面所提到的那些特性. 其實MySQL從來就不是完全免費的, 你無法用於商業用途. 而SQLite是完全的open的.
(二) SQLite SQL
SQLite的SQL從很大程度上實現了ANSI SQL92標準. 特別的SQLite支持視圖, 觸發器, 事務, 支持嵌套SQL. 這些都會在下面應用的過程中講到, 故這邊先暫時放下, 而主要說說SQLite所不支持的一些SQL.
1. 不支持Exists, 雖然支持in(in是Exists的一種情況)
2. 不支持多數據庫, 如: create table db1.table1 as select * from db2.table1;
3. 不支持存儲過程
4. 不支持Alter View/Trigger/Table
5. 不支持Truncate, 在SQLite中Delete不帶Where字句時和Truncate的效果是一樣的.
6. 不支持Floor和Ceiling函數, 還有其他蠻多的函數
7. 沒有Auto Increment(自增)字段, 但是SQLite其實是支持Auto Increment的, 即在將該字段設置為」 INTEGER PRIMARY KEY」的時候.
8. 不支持If Exists
……
詳細的SQL支持可以訪問: http://www.sqlite.org/lang.htm
詳細的不支持SQL可以訪問: http://www.sqlite.org/cvstrac/wiki?p=UnsupportedSql
(三) SQLite的數據類型
首先你會接觸到一個讓你驚訝的名詞: Typelessness(無類型). 對! SQLite是無類型的. 這意味著你可以保存任何類型的數據到你所想要保存的任何表的任何列中, 無論這列聲明的數據類型是什麼(只有在一種情況下不是, 稍後解釋). 對於SQLite來說對字段不指定類型是完全有效的. 如:
Create Table ex1(a, b, c);
誠然SQLite允許忽略數據類型, 但是仍然建議在你的Create Table語句中指定數據類型. 因為數據類型對於你和其他的程序員交流, 或者你準備換掉你的數據庫引擎. SQLite支持常見的數據類型, 如:
CREATE TABLE ex2(
a VARCHAR(10),
b NVARCHAR(15),
c TEXT,
d INTEGER,
e FLOAT,
f BOOLEAN,
g CLOB,
h BLOB,
i TIMESTAMP,
j NUMERIC(10,5)
k VARYING CHARACTER (24),
l NATIONAL VARYING CHARACTER(16)
);
前面提到在某種情況下, SQLite的字段並不是無類型的. 即在字段類型為」Integer Primary Key」時.
(四) SQLite的Wrapper
由於SQLite有別於其他數據庫引擎的TCP/IP或RPC訪問方式, 完全地是本地的操作, 從某種角度來說你可以說SQLite和MS的Access很相似, 但是更小更強大. 所謂Wrapper即使對SQLite提供的接口進行封裝, 使其他語言可以訪問, 使用SQLite.
SQLite本身是提供C和Tcl的接口的. 所以可以非常輕易的和PHP相結合. 除了PHP的Wrapper以外, 還有許多世界各地的程序員提供了各種語言的SQLite的接口封裝, 如Python, C++, Java, .Net…… 所流行的語言基本都有.
(五) PHP的環境下使用SQLite
1. PHP下的安裝
在PHP5中, SQLite已作為默認支持的模塊.在PHP4中你需要進行安裝. 首先去http://pecl.php.net/package/SQLite 去下載到SQLite的擴展, 注意Windows下的版本需要去http://snaps.php.net/win32/PECL_STABLE/php_sqlite.dll 下載, 當然你也可以下載代碼自己編譯.事實上在linux下只需要使用命令: 『pear install sqlite』就可以完成安裝,而在Win下需要修改php.ini, 同樣的使PHP4支持SQLite.
此時你已經無需再安裝任何東西了, 而你也已經完全支持SQLite了, 一個簡單, 快速, 可靠的數據庫.
如果你需要一個管理軟件, 那麼你可以嘗試使用SQLiteManager (www.sqlitemanager.org), 一個與PHPMyAdmin類似的針對SQLite的數據庫管理系統.
該系統的界面大致如下:
2. 第一個使用SQLite的PHP程序.
我們創建一個叫binzy的數據庫, 並創建一個叫Binzy的Table, 有2個字段, 分別是ID, Title. 而其中ID為INTEGER PRIMARY KEY, 即自增三主鍵. 並在其中插入了2條數據」Binzy」, 「Jasmin」.
打開並顯示數據:
if ($db = sqlite_open('../binzy.db', 0666, $sqliteerror))
{ // 打開
SQLite$result = sqlite_query($db,'select * from Binzy'); // 查詢while($row = sqlite_fetch_array($result)) // 獲得結果
{
print 'ID=>'.$row['MyID'].', Name=>'.$row['Name'].'
';
}
} else {die ($sqliteerror);}
結果如下,
接下來Insert一條記錄, 其中我們會使用到SQLite的事務.
if ($db = sqlite_open('../binzy.db', 0666, $sqliteerror)) {
sqlite_query($db,'BEGIN TRANSACTION'); // 開始事務
if (@sqlite_query($db,'insert into Binzy (Name) values (\'Binzy&Jasmin\')'))
{
print 'Execute Successfully';
sqlite_query($db,'COMMIT TRANSACTION'); // 提交事務
}
else
{
print sqlite_error_string(sqlite_last_error($db));
sqlite_query($db,'ROLLBACK TRANSACTION'); // 回滾事務
}
} else {
die ($sqliteerror);
}
如果執行失敗, 便會出現這樣的畫面,
成功則是這樣的,
是的, 如果你已經熟悉使用PHP對MySQL之類的數據庫進行操作, 那麼SQLite幾乎是一樣的, 而且更為簡潔.
3. 使用Pear::DB (PHP4中)
上面的例子中我們是使用PHP的函數直接對SQLite進行訪問, 這樣的訪問方式是不推薦使用的. 更好的方式是使用某種數據訪問抽像層, 如Pear的DB. 下面是2中查詢例子的重寫. 使用某個數據訪問抽像層會更方便更安全, 並且可以在需要進行數據庫遷移的時候盡可能減小成本.
require_once('DB.php');
$dbh = DB::connect('sqlite://@localhost/../binzy.db?mode=0666'); // 打開
$dbh->setFetchMode(DB_FETCHMODE_ASSOC);
if (!DB::isError($dbh))
{
$result = $dbh->query('select * from Binzy'); // 查詢
if (!DB::isError($result))
{
while($row = $result->fetchRow()) // 讀取
{ print 'ID=>'.$row['MyID'].', Name=>'.$row['Name'].'
';
}
$dbh->disconnect();
}
else
{
print($dbh->message);
$dbh->disconnect();
}
}
else
{
print($dbh->message);
$dbh->disconnect();
}
4. 使用Creole (PHP5中)
Creole是由phpdb.org開發的面向PHP5的數據訪問抽像層. 關於Creole可參考本期中的《Creole :新興數據抽像層》.
Pear::DB並沒有針對PHP5進行改變, 只是因為PHP5對PHP4良好的兼容性, 使得Pear::DB在PHP5下仍能很好的工作. 所以在你使用PHP5的時候推薦使用Creole.
require_once('creole/Creole.php');
$Connection = null;
try{
$Connection = Creole::getConnection('sqlite://@localhost/../binzy.db?mode=0644'); // 獲得Connection
$rs = $Connection->executeQuery('select * from Binzy'); // Get ResultSet while($rs->next())
{
print 'ID=>'.$rs->getInt('myid').', Name=>'.$rs->getString('name').'
';
}
$Connection->close();
}
catch(SQLException $exception) // Catch Exception
{
$Connection->close();
print $exception->getMessage();
}
(六) 總結
隨著PHP5的即將到來, 給我們帶來了許多新的語言特性, 使PHP更加適合於構建強大健壯的各類系統. 而隨著PHP5一起走進PHP開發人員視線的SQLite則給我們帶來了有別於MySQL的驚喜. 是的, 他簡單卻又強大, 穩定. 而在剛剛過去的六月底新版本的SQLite3已經Release了第一個測試版本, 不僅僅帶來了新的文件結構, 也帶來了許多新的特性.
PHP操作XML詳解
XML是一种流行的半结构化文件格式,以一种类似数据库的格式存储数据。在实际应用中,一些简单的、安全性较低的数据往往使用 XML文件的格式进行存储。这样做的好处一方面可以通过减少与数据库的交互性操作提高读取效率,另一方面可以有效利用 XML的优越性降低程序的编写难度。
PHP提供了一整套的读取 XML文件的方法,很容易的就可以编写基于 XML的脚本程序。本章将要介绍 PHP与 XML的操作方法,并对几个常用的 XML类库做一些简要介绍。
1 XML简介
XML是“可扩展性标识语言(eXtensible Markup Language)”的缩写,是一种类似于 HTML的标记性语言。但是与 HTML不同,XML主要用于描述数据和存放数据,而 HTML主要用于显示数据。
XML是一种“元标记”语言,开发者可以根据自己的需要创建标记的名称。例如,下面的 XML代码可以用来描述一条留言。
复制代码
Welcome
Simon
Welcome to XML guestbook!!
其中,与 标签标记了这是一段留言。在留言中有标题、作者、内容,完整的表述了一条留言信息。
在一个 XML文件的顶部,通常使用来标识 XML数据的开始和 XML数据使用标准的版本信息。在浏览器中访问 XML文件可以看到层次分明的 XML数据信息,如图 1所示。
[attachment=207463]
XML的发展非常迅速,近些年来很多软件开发商都开始采用 XML的开发标准进行应用程序的开发。并且,很多新兴技术都架构在 XML数据之上。这意味着 XML将与 HTML一样成为 Web技术不可或缺的一部分。
2 简单的 XML操作
在实际应用中,PHP与 XML的交互操作应用非常广泛。SimpleXML组件是 PHP5新增加的一个简
单的 XML操作组件,与传统的 XML组件相比,SimpleXML组件的使用非常简单。本节将对使用
SimpleXML组件操作 XML的方法做一下详细介绍。
2.1 创建一个 SimpleXML对象
SimpleXML对象是用来临时存储 XML数据的临时变量,对 XML进行的操作都是通过操作 SimpleXML对象来完成的。SimpleXML组件提供了两种创建 SimpleXML对象的方法。第一种方法是使用 simplexml_load_string函数读取一个字符串型变量中的 XML数据来完成创建的,其语法格式如下所示。
simplexml_load_string(string data)
这里的 data变量用于存储 XML数据。以下代码使用 simplexml_load_string函数创建了一个 SimpleXML对象
复制代码
$data = <<
production support
100001
Simon
24
1982-11-06
5000.00
1000.00
100002
Elaine
24
1982-01-01
6000.00
2000.00
testing center
110001
Helen
23
1983-07-21
5000.00
1000.00
XML;
$xml = simplexml_load_string($data); //创建 SimpleXML对象
print_r($xml); //输出 XML
?>
在上面的例子中,$data变量存储了一段 XML数据。 simplexml_load_string函数将变量$data转化成 SimpleXML对象。通过 print_r函数的输出可以看出该对象的结构,运行结果如下所示。
复制代码
SimpleXMLElement Object
(
[depart] => Array
(
[0] => SimpleXMLElement Object
(
[name] => production support
[employees] => SimpleXMLElement Object
( [employee] => Array (
[0] => SimpleXMLElement Object
( [serial_no] => 100001
[name] => Simon
[age] => 24
[birthday] => 1982-11-06
[salary] => 5000.00
[bonus] => 1000.00
)
[1] => SimpleXMLElement Object
( [serial_no] => 100002
[name] => Elaine
[age] => 24
[birthday] => 1982-01-01
[salary] => 6000.00
[bonus] => 2000.00
)
)
)
)
[1] => SimpleXMLElement Object
(
[name] => testing center
[employees] => SimpleXMLElement Object
(
[employee] => SimpleXMLElement Object
(
[serial_no] => 110001
[name] => Helen
[age] => 23
[birthday] => 1983-07-21
[salary] => 5000.00
[bonus] => 1000.00
)
)
)
)
)
从输出结果可以看出,SimpleXML对象的结构与 XML数据的格式完全相同。
第二种方法是使用 simplexml_load_flie函数读取一个 XML文件来完成创建的,其语法格式如下所示。
simplexml_load_file(string filename)
这里的 filename变量是用于存储 XML数据文件的文件名及其所在路径。以下代码使用 simplexml_load_file函数来创建了一个 SimpleXML对象。
复制代码
$xml = simplexml_load_file(’example.xml’); //创建 SimpleXML对象
print_r($xml); //输出 XML
?>
其中,example.xml存储的数据与上面的$data完全相同,运行结果也与上面完全相同。
上面两种方法实现了同样的功能,其区别就在于 XML的数据源不同。如果 XML的数据源在 PHP脚本文件中,则需要使用 simplexml_load_string来进行创建。如果 XML的数据源在一个单独的 XML文件中,则需要使用 simplexml_load_file来进行创建。
2.2 读取 SimpleXML对象中的 XML数据
前面介绍了使用 print_r函数来读取 SimpleXML对象中的数据,其返回结果与数组的结构类似。显然,这种显示方式在实际应用中是不可取的。在这里将介绍其他的几种读取 SimpleXML对象中 XML数据的方法。
1.var_dump函数显示对象详细信息
var_dump函数可以用于显示 SimpleXML对象的详细信息,与 print_r函数相比,var_dump函数显示的信息更为完整,其语法如下所示。
void var_dump(object1, object2 … )
以下代码使用 var_dump函数输出了上面例子中对象的详细信息。
复制代码
?>
运行结果如下所示。
复制代码
object(SimpleXMLElement)#1 (1) { ["depart"]=> array(2) {
[0]=>
object(SimpleXMLElement)#2 (2) {
["name"]=>
string(18) “production support”
["employees"]=>
object(SimpleXMLElement)#4 (1) {
["employee"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#5 (6) {
["serial_no"]=>
string(6) “100001″
["name"]=>
string(5) “Simon”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-11-06″
["salary"]=>
string(7) “5000.00″
["bonus"]=>
string(7) “1000.00″
}
[1]=>
object(SimpleXMLElement)#6 (6) {
["serial_no"]=>
string(6) “100002″
["name"]=>
string(6) “Elaine”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-01-01″
["salary"]=>
string(7) “6000.00″
["bonus"]=>
string(7) “2000.00″
}
}
}
}
[1]=>
object(SimpleXMLElement)#3 (2) {
["name"]=>
string(14) “testing center”
["employees"]=>
object(SimpleXMLElement)#7 (1) {
["employee"]=>
object(SimpleXMLElement)#8 (6) {
["serial_no"]=>
string(6) “110001″
["name"]=>
string(5) “Helen”
["age"]=>
string(2) “23″
["birthday"]=>
string(10) “1983-07-21″
["salary"]=>
string(7) “5000.00″
["bonus"]=>
string(7) “1000.00″
}
}
}
}
}
与前面 print_r输出的结果相比较,var_dump函数的输出结果的结构更为严谨,并且将对象中的每一个属性的数据类型均作出分析。在实际应用中,var_dump函数往往用于程序调试时的对象检测。
2.读取 XML数据中的标签
与操作数组类型的变量类似,读取 XML也可以通过类似的方法来完成。例如,如果需要读取上面 XML数据中每一个“ depart”标签下的“name”属性,可以通过使用 foreach函数来完成,如以下代码
所示。
复制代码
depart as $a)
{
echo “$a->name
”;
}
?>
运行结果如下所示。
production support
testing center
//读取 XML文件 //循环读取 XML数据中的每一个 depart标签
//输出其中的 name属性
也可以使用方括号“ []”来直接读取 XML数据中指定的标签。以下代码输出了上面 XML数据中的第一个“depart”标签的“name”属性。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML文件
echo $xml->depart->name[0]; //输出节点
?>
运行结果如下所示。
production support
对于一个标签下的所有子标签,SimpleXML组件提供了 children方法进行读取。例如,对于上面的 XML数据中的“ depart”标签,其下包括两个子标签:“ name”和“employees”。以下代码实现了对第一个“depart”标签下的子标签的读取。
复制代码
$xml = simplexml_load_file(’example.xml’);
foreach ($xml->depart->children() as $depart) //循环读取 depart标签下的子标签
{
var_dump($depart); //输出标签的 XML数据
}
?>
运行结果如下所示。
复制代码
object(SimpleXMLElement)#3 (1) {
[0]=>
string(18) “production support”
}
object(SimpleXMLElement)#5 (1) {
["employee"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#3 (6) {
["serial_no"]=>
string(6) “100001″
["name"]=>
string(5) “Simon”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-11-06″
["salary"]=>
string(7) “5000.00″
["bonus"]=>
string(7) “1000.00″
}
[1]=>
object(SimpleXMLElement)#6 (6) {
["serial_no"]=>
string(6) “100002″
["name"]=>
string(6) “Elaine”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-01-01″
["salary"]=>
string(7) “6000.00″
["bonus"]=>
string(7) “2000.00″
}
}
}
可以看出,使用 children方法后,所有的子标签均被当作一个新的 XML文件进行处理。
3.基于 XML数据路径的查询
SimpleXML组件提供了一种基于 XML数据路径的查询方法。 XML数据路径即从 XML的根到某一个标签所经过的全部标签。这种路径使用斜线“ /”隔开标签名。例如,对于上面的 XML数据,要查询所有的标签“name”中的值,从根开始要经过 departs、depart、employees和 employee标签,则其路径
为“/departs/depart/employees/employee/name”。 SimpleXML组件使用 xpath方法来解析路径,其语法格式如下所示。
xpath(string path)
其中的 path为路径。该方法返回了一个包含有所有要查询标签值的数组。以下代码查询了上面 XML数据中的所有 name标签。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML文件
$result = $xml->xpath(’/departs/depart/employees/employee/name’); //定义节点
var_dump($result); //输出节点
?>
运行结果如下所示。
复制代码
array(3) {
[0]=> object(SimpleXMLElement)#2 (1) {
[0]=> string(5) “Simon”
}
[1]=> object(SimpleXMLElement)#3 (1) {
[0]=> string(6) “Elaine”
}
[2]=> object(SimpleXMLElement)#4 (1) {
[0]=> string(5) “Helen”
}
}
可以看出,所有的 name标签均被查询出来。
2.3 XML数据的修改
对于 XML数据的修改与读取 XML数据中的标签方法类似。即通过直接修改 SimpleXML对象中的标签的值来实现。以下代码实现了对上面 XML数据中第一个“ depart”标签的“ name”子标签的修改。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML
$xml->depart->name[0] = “Human Resource”; //修改节点
?>
修改后,并不会对 XML文件有任何影响。但是,在程序中,对于 SimpleXML对象的读取将使用修改过的值。
2.4 标准化 XML数据
SimpleXML还提供了一种标准化 XML数据的方法 asXML。asXML方法可以有效的将 SimpleXML对象中的内容按照 XML 1.0标准进行重新编排并以字符串的数据类型返回。以下代码实现了对上面 XML数据的标准化。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML数据
echo $xml->asXML(); //标准化 XML数据
?>
2.5 XML数据的存储
将 SimpleXML对象中的 XML数据存储到一个 XML文件的方法非常简单,即将 asXML方法的返回结果输出到一个文件中即可。以下代码首先将 XML文件中的 depart name进行了修改,然后将修改过的 XML数据输出到另一个 XML文件。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML数据
$newxml = $xml->asXML(); //标准化 XML数据
$fp = fopen(”newxml.xml”, “w”); //打开要写入 XML数据的文件
fwrite($fp, $newxml); //写入 XML数据
fclose($fp); //关闭文件
?>
代码运行后,可以看到在 newxml.xml文件中的 XML数据如下所示。
复制代码
Human Resource
100001
Simon
24
1982-11-06
5000.00
1000.00
100002
Elaine
24
1982-01-01
6000.00
2000.00
testing center
110001
Helen
23
1983-07-21
5000.00
1000.00
可以看出,对于 XML文件的修改已经保存到输出文件中了。
3 XML文档的动态创建
在实际应用中,时而会需要动态生成 XML文档的操作。前面介绍的 SimpleXML组件并不提供创建 XML文档的方法。因此,如果需要动态创建 XML文档,往往使用 DOM组件进行创建。 DOM是文档对象模型 Document Object Model的缩写, DOM组件提供了对 XML文档的树型解析模式。以下代码使用 DOM组件创建了一个 XML文档。
复制代码
//创建一个新的 DOM文档
$dom = new DomDocument();
//在根节点创建 departs标签
$departs = $dom->createElement(’departs’);
$dom->appendChild($departs);
//在 departs标签下创建 depart子标签
$depart = $dom->createElement(’depart’);
$departs->appendChild($depart);
//在 depart标签下创建 employees子标签
$employees = $dom->createElement(’employees’);
$depart->appendChild($employees);
//在 employees标签下创建 employee子标签
$employee = $dom->createElement(’employee’);
$employees->appendChild($employee);
//在 employee标签下创建 serial_no子标签
$serial_no = $dom->createElement(’serial_no’);
$employee->appendChild($serial_no);
//为 serial_no标签添加值节点 100001
$serial_no_value = $dom->createTextNode(’100001′);
$serial_no->appendChild($serial_no_value);
//输出 XML数据
echo $dom->saveXML();
?>
输出结果如下所示。
100001
DOM组件除了可以用来动态创建 XML文档外,还可以用来读取 XML文件。以下代码实现了对前
面 XML文件的读取。
复制代码
$dom = new DomDocument(); //创建 DOM对象
$dom->load(’example.xml’); //读取 XML文件
$root = $dom->documentElement; //获取 XML数据的根
read_child($root); //调用 read_child函数读取根对象
function read_child($node)
{
$children = $node->childNodes; //获得$node的所有子节点
foreach($children as $e) //循环读取每一个子节点
{
if($e->nodeType == XML_TEXT_NODE) //如果子节点为文本型则输出
{
echo $e->nodeValue.”
”;
}
else if($e->nodeType == XML_ELEMENT_NODE) //如果子节点为节点对象,则调用函数处理
{
read_child($e);
}
}
}
?>
运行结果如下所示。
引用
production support
100001
Simon
24
1982-11-06
5000.00
1000.00
100002
Elaine
24
1982-01-01
6000.00
2000.00
testing center
110001
Helen
23
1983-07-21
5000.00
1000.00
上面的例子使用了递归的方式对 XML数据进行了处理,实现了输出 XML数据中的所有文本型标签的功能。
4 XML应用实例——留言本
前面介绍了 XML的基本操作,本节将以设计一个 XML留言本为例来详细说明在实际应用中如何实现 PHP与 XML数据的交互操作。
4.1 XML文件结构设计
XML文件用于存储 XML数据,也就是留言本中的留言。这里,对于每条留言,在 XML数据中主要包括三项内容:留言标题、留言者姓名、留言内容。因此,将 XML文件的格式设计如下。
复制代码
这里是留言的标题
这里是留言者
这里是留言内容
4.2 提交页面的编写
提交留言页面由两个页面组成。一个是让访问者用来书写留言的表单的 HTML文件,一个是用来处理访问者输入的 PHP脚本。表单的 HTML代码如下所示。
复制代码
发表新的留言
对于用来处理用户输入的 PHP脚本,其基本逻辑是首先创建一个 DOM对象,然后读取 XML文件中的 XML数据,接下来在 XML对象上创建新的节点并将用户的输入储存起来,最后将 XML数据输出到原来的 XML文件中。具体实现代码如下所示。
复制代码
$guestbook = new DomDocument(); //创建一个新的 DOM对象
$guestbook->load(’DB/guestbook.xml’); //读取 XML数据
$threads = $guestbook->documentElement; //获得 XML结构的根
//创建一个新 thread节点
$thread = $guestbook->createElement(’thread’);
$threads->appendChild($thread);
//在新的 thread节点上创建 title标签
$title = $guestbook->createElement(’title’);
$title->appendChild($guestbook->createTextNode($_POST['title']));
$thread->appendChild($title);
//在新的 thread节点上创建 author标签
$author = $guestbook->createElement(’author’);
$author->appendChild($guestbook->createTextNode($_POST['author']));
$thread->appendChild($author);
//在新的 thread节点上创建 content标签
$content = $guestbook->createElement(’content’);
$content->appendChild($guestbook->createTextNode($_POST['content']));
$thread->appendChild($content);
//将 XML数据写入文件
$fp = fopen(”DB/guestbook.xml”, “w”);
if(fwrite($fp, $guestbook->saveXML()))
echo “留言提交成功”;
else
echo “留言提交失败”;
fclose($fp);
?>
在浏览器中运行上述 HTML文件并填写适当的留言内容,如图 2所示。
[attachment=207464]
图 2 发表新留言界面
单击【Submit】按钮后,XML文件中的内容如下所示。
复制代码
Welcome
Simon
Welcome to XML guestbook!!
可以看到 XML文件中已经将留言存储起来了。
4.3 显示页面的编写
显示页面可以使用前面介绍的 SimpleXML组件很容易的实现,具体实现代码如下所示。
复制代码
//打开用于存储留言的 XML文件
$guestbook = simplexml_load_file(’DB/guestbook.xml’);
foreach($guestbook->thread as $th) //循环读取 XML数据中的每一个 thread标签
{
echo “标题:”.$th->title.”
”;
echo “作者:”.$th->author.”
”;
echo “内容:
echo “
”;
}
?>
摘自:http://www.phpwind.net/simple/?t812699.html
PHP提供了一整套的读取 XML文件的方法,很容易的就可以编写基于 XML的脚本程序。本章将要介绍 PHP与 XML的操作方法,并对几个常用的 XML类库做一些简要介绍。
1 XML简介
XML是“可扩展性标识语言(eXtensible Markup Language)”的缩写,是一种类似于 HTML的标记性语言。但是与 HTML不同,XML主要用于描述数据和存放数据,而 HTML主要用于显示数据。
XML是一种“元标记”语言,开发者可以根据自己的需要创建标记的名称。例如,下面的 XML代码可以用来描述一条留言。
复制代码
其中,
在一个 XML文件的顶部,通常使用来标识 XML数据的开始和 XML数据使用标准的版本信息。在浏览器中访问 XML文件可以看到层次分明的 XML数据信息,如图 1所示。
[attachment=207463]
XML的发展非常迅速,近些年来很多软件开发商都开始采用 XML的开发标准进行应用程序的开发。并且,很多新兴技术都架构在 XML数据之上。这意味着 XML将与 HTML一样成为 Web技术不可或缺的一部分。
2 简单的 XML操作
在实际应用中,PHP与 XML的交互操作应用非常广泛。SimpleXML组件是 PHP5新增加的一个简
单的 XML操作组件,与传统的 XML组件相比,SimpleXML组件的使用非常简单。本节将对使用
SimpleXML组件操作 XML的方法做一下详细介绍。
2.1 创建一个 SimpleXML对象
SimpleXML对象是用来临时存储 XML数据的临时变量,对 XML进行的操作都是通过操作 SimpleXML对象来完成的。SimpleXML组件提供了两种创建 SimpleXML对象的方法。第一种方法是使用 simplexml_load_string函数读取一个字符串型变量中的 XML数据来完成创建的,其语法格式如下所示。
simplexml_load_string(string data)
这里的 data变量用于存储 XML数据。以下代码使用 simplexml_load_string函数创建了一个 SimpleXML对象
复制代码
$data = <<
XML;
$xml = simplexml_load_string($data); //创建 SimpleXML对象
print_r($xml); //输出 XML
?>
在上面的例子中,$data变量存储了一段 XML数据。 simplexml_load_string函数将变量$data转化成 SimpleXML对象。通过 print_r函数的输出可以看出该对象的结构,运行结果如下所示。
复制代码
SimpleXMLElement Object
(
[depart] => Array
(
[0] => SimpleXMLElement Object
(
[name] => production support
[employees] => SimpleXMLElement Object
( [employee] => Array (
[0] => SimpleXMLElement Object
( [serial_no] => 100001
[name] => Simon
[age] => 24
[birthday] => 1982-11-06
[salary] => 5000.00
[bonus] => 1000.00
)
[1] => SimpleXMLElement Object
( [serial_no] => 100002
[name] => Elaine
[age] => 24
[birthday] => 1982-01-01
[salary] => 6000.00
[bonus] => 2000.00
)
)
)
)
[1] => SimpleXMLElement Object
(
[name] => testing center
[employees] => SimpleXMLElement Object
(
[employee] => SimpleXMLElement Object
(
[serial_no] => 110001
[name] => Helen
[age] => 23
[birthday] => 1983-07-21
[salary] => 5000.00
[bonus] => 1000.00
)
)
)
)
)
从输出结果可以看出,SimpleXML对象的结构与 XML数据的格式完全相同。
第二种方法是使用 simplexml_load_flie函数读取一个 XML文件来完成创建的,其语法格式如下所示。
simplexml_load_file(string filename)
这里的 filename变量是用于存储 XML数据文件的文件名及其所在路径。以下代码使用 simplexml_load_file函数来创建了一个 SimpleXML对象。
复制代码
$xml = simplexml_load_file(’example.xml’); //创建 SimpleXML对象
print_r($xml); //输出 XML
?>
其中,example.xml存储的数据与上面的$data完全相同,运行结果也与上面完全相同。
上面两种方法实现了同样的功能,其区别就在于 XML的数据源不同。如果 XML的数据源在 PHP脚本文件中,则需要使用 simplexml_load_string来进行创建。如果 XML的数据源在一个单独的 XML文件中,则需要使用 simplexml_load_file来进行创建。
2.2 读取 SimpleXML对象中的 XML数据
前面介绍了使用 print_r函数来读取 SimpleXML对象中的数据,其返回结果与数组的结构类似。显然,这种显示方式在实际应用中是不可取的。在这里将介绍其他的几种读取 SimpleXML对象中 XML数据的方法。
1.var_dump函数显示对象详细信息
var_dump函数可以用于显示 SimpleXML对象的详细信息,与 print_r函数相比,var_dump函数显示的信息更为完整,其语法如下所示。
void var_dump(object1, object2 … )
以下代码使用 var_dump函数输出了上面例子中对象的详细信息。
复制代码
?>
运行结果如下所示。
复制代码
object(SimpleXMLElement)#1 (1) { ["depart"]=> array(2) {
[0]=>
object(SimpleXMLElement)#2 (2) {
["name"]=>
string(18) “production support”
["employees"]=>
object(SimpleXMLElement)#4 (1) {
["employee"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#5 (6) {
["serial_no"]=>
string(6) “100001″
["name"]=>
string(5) “Simon”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-11-06″
["salary"]=>
string(7) “5000.00″
["bonus"]=>
string(7) “1000.00″
}
[1]=>
object(SimpleXMLElement)#6 (6) {
["serial_no"]=>
string(6) “100002″
["name"]=>
string(6) “Elaine”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-01-01″
["salary"]=>
string(7) “6000.00″
["bonus"]=>
string(7) “2000.00″
}
}
}
}
[1]=>
object(SimpleXMLElement)#3 (2) {
["name"]=>
string(14) “testing center”
["employees"]=>
object(SimpleXMLElement)#7 (1) {
["employee"]=>
object(SimpleXMLElement)#8 (6) {
["serial_no"]=>
string(6) “110001″
["name"]=>
string(5) “Helen”
["age"]=>
string(2) “23″
["birthday"]=>
string(10) “1983-07-21″
["salary"]=>
string(7) “5000.00″
["bonus"]=>
string(7) “1000.00″
}
}
}
}
}
与前面 print_r输出的结果相比较,var_dump函数的输出结果的结构更为严谨,并且将对象中的每一个属性的数据类型均作出分析。在实际应用中,var_dump函数往往用于程序调试时的对象检测。
2.读取 XML数据中的标签
与操作数组类型的变量类似,读取 XML也可以通过类似的方法来完成。例如,如果需要读取上面 XML数据中每一个“ depart”标签下的“name”属性,可以通过使用 foreach函数来完成,如以下代码
所示。
复制代码
depart as $a)
{
echo “$a->name
”;
}
?>
运行结果如下所示。
production support
testing center
//读取 XML文件 //循环读取 XML数据中的每一个 depart标签
//输出其中的 name属性
也可以使用方括号“ []”来直接读取 XML数据中指定的标签。以下代码输出了上面 XML数据中的第一个“depart”标签的“name”属性。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML文件
echo $xml->depart->name[0]; //输出节点
?>
运行结果如下所示。
production support
对于一个标签下的所有子标签,SimpleXML组件提供了 children方法进行读取。例如,对于上面的 XML数据中的“ depart”标签,其下包括两个子标签:“ name”和“employees”。以下代码实现了对第一个“depart”标签下的子标签的读取。
复制代码
$xml = simplexml_load_file(’example.xml’);
foreach ($xml->depart->children() as $depart) //循环读取 depart标签下的子标签
{
var_dump($depart); //输出标签的 XML数据
}
?>
运行结果如下所示。
复制代码
object(SimpleXMLElement)#3 (1) {
[0]=>
string(18) “production support”
}
object(SimpleXMLElement)#5 (1) {
["employee"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#3 (6) {
["serial_no"]=>
string(6) “100001″
["name"]=>
string(5) “Simon”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-11-06″
["salary"]=>
string(7) “5000.00″
["bonus"]=>
string(7) “1000.00″
}
[1]=>
object(SimpleXMLElement)#6 (6) {
["serial_no"]=>
string(6) “100002″
["name"]=>
string(6) “Elaine”
["age"]=>
string(2) “24″
["birthday"]=>
string(10) “1982-01-01″
["salary"]=>
string(7) “6000.00″
["bonus"]=>
string(7) “2000.00″
}
}
}
可以看出,使用 children方法后,所有的子标签均被当作一个新的 XML文件进行处理。
3.基于 XML数据路径的查询
SimpleXML组件提供了一种基于 XML数据路径的查询方法。 XML数据路径即从 XML的根到某一个标签所经过的全部标签。这种路径使用斜线“ /”隔开标签名。例如,对于上面的 XML数据,要查询所有的标签“name”中的值,从根开始要经过 departs、depart、employees和 employee标签,则其路径
为“/departs/depart/employees/employee/name”。 SimpleXML组件使用 xpath方法来解析路径,其语法格式如下所示。
xpath(string path)
其中的 path为路径。该方法返回了一个包含有所有要查询标签值的数组。以下代码查询了上面 XML数据中的所有 name标签。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML文件
$result = $xml->xpath(’/departs/depart/employees/employee/name’); //定义节点
var_dump($result); //输出节点
?>
运行结果如下所示。
复制代码
array(3) {
[0]=> object(SimpleXMLElement)#2 (1) {
[0]=> string(5) “Simon”
}
[1]=> object(SimpleXMLElement)#3 (1) {
[0]=> string(6) “Elaine”
}
[2]=> object(SimpleXMLElement)#4 (1) {
[0]=> string(5) “Helen”
}
}
可以看出,所有的 name标签均被查询出来。
2.3 XML数据的修改
对于 XML数据的修改与读取 XML数据中的标签方法类似。即通过直接修改 SimpleXML对象中的标签的值来实现。以下代码实现了对上面 XML数据中第一个“ depart”标签的“ name”子标签的修改。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML
$xml->depart->name[0] = “Human Resource”; //修改节点
?>
修改后,并不会对 XML文件有任何影响。但是,在程序中,对于 SimpleXML对象的读取将使用修改过的值。
2.4 标准化 XML数据
SimpleXML还提供了一种标准化 XML数据的方法 asXML。asXML方法可以有效的将 SimpleXML对象中的内容按照 XML 1.0标准进行重新编排并以字符串的数据类型返回。以下代码实现了对上面 XML数据的标准化。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML数据
echo $xml->asXML(); //标准化 XML数据
?>
2.5 XML数据的存储
将 SimpleXML对象中的 XML数据存储到一个 XML文件的方法非常简单,即将 asXML方法的返回结果输出到一个文件中即可。以下代码首先将 XML文件中的 depart name进行了修改,然后将修改过的 XML数据输出到另一个 XML文件。
复制代码
$xml = simplexml_load_file(’example.xml’); //读取 XML数据
$newxml = $xml->asXML(); //标准化 XML数据
$fp = fopen(”newxml.xml”, “w”); //打开要写入 XML数据的文件
fwrite($fp, $newxml); //写入 XML数据
fclose($fp); //关闭文件
?>
代码运行后,可以看到在 newxml.xml文件中的 XML数据如下所示。
复制代码
可以看出,对于 XML文件的修改已经保存到输出文件中了。
3 XML文档的动态创建
在实际应用中,时而会需要动态生成 XML文档的操作。前面介绍的 SimpleXML组件并不提供创建 XML文档的方法。因此,如果需要动态创建 XML文档,往往使用 DOM组件进行创建。 DOM是文档对象模型 Document Object Model的缩写, DOM组件提供了对 XML文档的树型解析模式。以下代码使用 DOM组件创建了一个 XML文档。
复制代码
//创建一个新的 DOM文档
$dom = new DomDocument();
//在根节点创建 departs标签
$departs = $dom->createElement(’departs’);
$dom->appendChild($departs);
//在 departs标签下创建 depart子标签
$depart = $dom->createElement(’depart’);
$departs->appendChild($depart);
//在 depart标签下创建 employees子标签
$employees = $dom->createElement(’employees’);
$depart->appendChild($employees);
//在 employees标签下创建 employee子标签
$employee = $dom->createElement(’employee’);
$employees->appendChild($employee);
//在 employee标签下创建 serial_no子标签
$serial_no = $dom->createElement(’serial_no’);
$employee->appendChild($serial_no);
//为 serial_no标签添加值节点 100001
$serial_no_value = $dom->createTextNode(’100001′);
$serial_no->appendChild($serial_no_value);
//输出 XML数据
echo $dom->saveXML();
?>
输出结果如下所示。
DOM组件除了可以用来动态创建 XML文档外,还可以用来读取 XML文件。以下代码实现了对前
面 XML文件的读取。
复制代码
$dom = new DomDocument(); //创建 DOM对象
$dom->load(’example.xml’); //读取 XML文件
$root = $dom->documentElement; //获取 XML数据的根
read_child($root); //调用 read_child函数读取根对象
function read_child($node)
{
$children = $node->childNodes; //获得$node的所有子节点
foreach($children as $e) //循环读取每一个子节点
{
if($e->nodeType == XML_TEXT_NODE) //如果子节点为文本型则输出
{
echo $e->nodeValue.”
”;
}
else if($e->nodeType == XML_ELEMENT_NODE) //如果子节点为节点对象,则调用函数处理
{
read_child($e);
}
}
}
?>
运行结果如下所示。
引用
production support
100001
Simon
24
1982-11-06
5000.00
1000.00
100002
Elaine
24
1982-01-01
6000.00
2000.00
testing center
110001
Helen
23
1983-07-21
5000.00
1000.00
上面的例子使用了递归的方式对 XML数据进行了处理,实现了输出 XML数据中的所有文本型标签的功能。
4 XML应用实例——留言本
前面介绍了 XML的基本操作,本节将以设计一个 XML留言本为例来详细说明在实际应用中如何实现 PHP与 XML数据的交互操作。
4.1 XML文件结构设计
XML文件用于存储 XML数据,也就是留言本中的留言。这里,对于每条留言,在 XML数据中主要包括三项内容:留言标题、留言者姓名、留言内容。因此,将 XML文件的格式设计如下。
复制代码
4.2 提交页面的编写
提交留言页面由两个页面组成。一个是让访问者用来书写留言的表单的 HTML文件,一个是用来处理访问者输入的 PHP脚本。表单的 HTML代码如下所示。
复制代码
发表新的留言
对于用来处理用户输入的 PHP脚本,其基本逻辑是首先创建一个 DOM对象,然后读取 XML文件中的 XML数据,接下来在 XML对象上创建新的节点并将用户的输入储存起来,最后将 XML数据输出到原来的 XML文件中。具体实现代码如下所示。
复制代码
$guestbook = new DomDocument(); //创建一个新的 DOM对象
$guestbook->load(’DB/guestbook.xml’); //读取 XML数据
$threads = $guestbook->documentElement; //获得 XML结构的根
//创建一个新 thread节点
$thread = $guestbook->createElement(’thread’);
$threads->appendChild($thread);
//在新的 thread节点上创建 title标签
$title = $guestbook->createElement(’title’);
$title->appendChild($guestbook->createTextNode($_POST['title']));
$thread->appendChild($title);
//在新的 thread节点上创建 author标签
$author = $guestbook->createElement(’author’);
$author->appendChild($guestbook->createTextNode($_POST['author']));
$thread->appendChild($author);
//在新的 thread节点上创建 content标签
$content = $guestbook->createElement(’content’);
$content->appendChild($guestbook->createTextNode($_POST['content']));
$thread->appendChild($content);
//将 XML数据写入文件
$fp = fopen(”DB/guestbook.xml”, “w”);
if(fwrite($fp, $guestbook->saveXML()))
echo “留言提交成功”;
else
echo “留言提交失败”;
fclose($fp);
?>
在浏览器中运行上述 HTML文件并填写适当的留言内容,如图 2所示。
[attachment=207464]
图 2 发表新留言界面
单击【Submit】按钮后,XML文件中的内容如下所示。
复制代码
可以看到 XML文件中已经将留言存储起来了。
4.3 显示页面的编写
显示页面可以使用前面介绍的 SimpleXML组件很容易的实现,具体实现代码如下所示。
复制代码
//打开用于存储留言的 XML文件
$guestbook = simplexml_load_file(’DB/guestbook.xml’);
foreach($guestbook->thread as $th) //循环读取 XML数据中的每一个 thread标签
{
echo “标题:”.$th->title.”
”;
echo “作者:”.$th->author.”
”;
echo “内容:
”.$th->content.””;
echo “
”;
}
?>
摘自:http://www.phpwind.net/simple/?t812699.html
2010年10月18日 星期一
2010年10月4日 星期一
execute php.exe in PHP script
$script = $argv[1]
$params = implode(' ', array_slice($argv, 2));
$cmd = "{$script} {$params} > /dev/null &";
$output = array();
$return = 0;
exec("php {$cmd}", $output, $return);
exit((int)$return);
$params = implode(' ', array_slice($argv, 2));
$cmd = "{$script} {$params} > /dev/null &";
$output = array();
$return = 0;
exec("php {$cmd}", $output, $return);
exit((int)$return);
2010年10月3日 星期日
洋媳婦的教育方法...令中國婆婆大開眼界~
洋媳婦的教育方法...令中國婆婆大開眼界~
兒子去美國留學,畢業後定居美國。還給我找了個洋媳婦蘇珊。如今,小孫子托比已經3歲了。今年夏天,兒子為我申請了探親簽證。在美國待了三個月,洋媳婦蘇珊教育孩子的方法,令我這個中國婆婆大開眼界。
不吃飯就餓著
每天早上,托比醒來後,蘇珊把早餐往餐桌上一放,就自顧自地忙去了。托比會自己爬上凳子,喝牛奶,吃麵包片。吃飽後,他回自己的房間,在衣櫃裡找衣服、鞋子,再自己穿上。畢竟托比只有3歲,還搞不清楚子的正反面,分不清鞋子的左右腳。有一次托比又把褲子穿反了,我趕緊上前想幫他換,卻被蘇珊制止了。她說,如果他覺得不舒服,會自己脫下來,重新穿好;如果他沒覺得有什麼不舒服,那就隨他的便。那一整天,托比反穿著褲子跑來跑去,蘇姍像沒看見一樣。
又一會而,托比出去和鄰居家的小朋友玩,沒多久,氣喘吁吁地跑回家,對蘇珊說:「媽媽,露西說我的褲子穿反了,真的嗎?」露西是鄰居家的小姑娘,今年5 歲。蘇姍笑著說: 「是的,你要不要換回來?」托比點點頭,自己脫下褲子,仔細看了看,重新穿上了。從那以後,托比再也沒穿反過褲子。
我不禁想起,我的外孫女五六歲時不會用筷子,上小學時不會繫鞋帶。如今在上寄宿制初中的她,每個週末都要帶回家一大堆髒衣服呢。
一天中午,托比鬧情緒,不肯吃飯。蘇珊說了他幾句,憤怒地小托比一把將盤子推到了地上,盤子裡的食物灑了一地。蘇姍看著托比,認真地說:「看來你確實不想吃飯!記住,從現在到明天早上,你什麼都不能吃。」托比點點頭,堅定地回答:「Yes!」我在心裡暗笑,這母子倆,還都挺倔 !
下午,蘇珊和我商量,晚上由我做中國菜。我心領神會,托 比告別愛吃中國菜,一定是蘇珊覺得托比中午沒好好吃飯,想讓他晚上多吃點兒。
那天晚上我施展廚藝,做了托比最愛吃的糖醋裡脊、油悶大蝦,還用意大利麵做了中國式的涼麵。托比最喜歡吃那種涼麵,小小的人可以吃滿滿一大盤。
開始吃晚飯了,托比歡天喜地地爬上凳子。蘇珊卻走過來,拿走了他的盤子和刀叉,說:「我們已經約好了,今天你不能吃飯,你自己也答應了的。」托比看著面容嚴肅的媽媽,「哇」地一聲在哭起來,邊哭邊說:「媽媽,我餓,我要吃飯。」「不行,說過的話要算數。」蘇珊毫不心軟。
我心疼了,想替托比求情,說點好話,卻見兒子對我使眼色。想起我剛到美國時,兒子就跟我說,在美國,父母教育孩子時,別人千萬不要插手,即使是長輩也不例外。無奈,我! 只好保持沉默。
那頓飯,從始至終,可憐的小托比一直坐在玩具車裡,眼巴! 巴地看著我們三個大人狼吞虎嚥。我這才明白蘇珊讓我做中餐的真正用意。我相信,下一次,托比想發脾氣扔飯碗時,一定會想起自己餓著肚子看爸爸媽媽和奶奶享用美食的經歷。餓著肚子的滋味不好受,況且還是面對自己最喜愛的食物。
臨睡前,我和蘇珊一起去向托比道晚安。托比小心翼翼地問: 「媽媽,我很餓,現在我能吃中國面嗎?」蘇珊微笑著搖搖頭,堅決地說:「不!」托比嘆了口氣,又問:「那等我睡完覺睜開眼睛時,可以吃嗎?」「當然可以。」蘇珊溫柔地回答。托比甜甜地笑了。
大部分情況下,托比吃飯都很積極,他不想因為「罷吃」而錯過食物,再受餓肚子的苦。每當看到托比埋頭大口大口地! 吃飯,嘴上臉上粘的都是食物時,我就想起外孫女。她像托比這麼大時,為了哄她吃飯,幾個大人端著飯碗跟在她屁股後面跑,她還不買賬,還要談條件:吃完這碗買一個玩具,再吃一碗買一個玩具……
以其人之道,還治其人這身
有一天,我們帶托比去公園玩。很快,托比就和兩個女孩兒玩起了廚房遊戲。塑料小鍋、小鏟子、小盤子、小碗擺了一地。忽然,淘氣的托比拿起小鍋,使勁在一個女孩兒頭上敲了一下,女孩兒愣了一下,放聲大哭。另一個女孩兒年紀更小一些,見些情形,也被嚇得大哭起來。大概托比沒想到會有這麼嚴重的後果,站在一旁,愣住了。
蘇珊走上前,開清了事情的來龍去脈後,她一聲不吭,拿起小鍋,使勁敲到托比的頭上,托比沒防備,一下子跌坐在草地上,哇哇大哭起來。蘇珊問托比:「疼嗎?下次還這樣嗎?」 托比一邊哭,一邊拚命搖頭。? 說他以後再也不會這麼做了。
托比的舅舅送了他一輛淺藍色的小自行車,托比非常喜歡, 當成寶貝,不許別人碰。鄰居小姑娘露西是托比的好朋友,央求托比好幾次,要騎他的小車,托比都沒答應。
一次,幾個孩子一起玩時,露西趁托比不注意,偷偷騎上小車,揚長而去。托比發現後,氣憤地跑來向蘇珊告狀。蘇珊正和幾個孩子的母親一起聊天喝咖啡,便微笑著說:「你們的事情自己解決,媽媽可管不了。」托比無奈地走了。
過了一小會兒,露西騎著小車回來了。托比看到露西,一把將她推倒在地,搶過了小車。露西坐在地上大哭起來。蘇珊抱起露西,安撫了她一會兒。很快,露西就和別的小朋友興高采烈地玩了起來。
托比自己騎了會車,覺得有些無聊,看到那幾個孩子玩得那麼高興,他想加入,又覺得有些不好意思。他蹭到蘇珊身邊,嘟囔道:「媽媽,我想跟露西他們一起玩。」蘇珊不動聲色地說:「那你自己去找他們啦!」「媽媽,你陪我一起去。 」 托比懇求道。 「那可不行,剛才是你把露西弄哭的,現在你又想和大家玩,就得自己去解決問題。」
托比騎著小車慢慢靠近露西,快到她身邊時,又掉頭回來。來回好幾次,不知道從什麼時候開始,托比和露西又笑逐顏開,鬧成了一團。
管教孩子是父母的事
蘇珊的父母住在加利福尼亞州,聽說我來了,兩人開車來探望我們。家裡來了客人,托比很興奮,跑上跑下地亂竄。他把玩沙子用的小桶裝滿了水,提著小桶在屋裡四處轉悠。蘇珊警告了她好幾次,不要把水灑到地板上,托比置若罔聞。最後,托比還是把水桶弄倒了,水灑了一地。興奮的小托比不覺得自己做錯了事,還得意地光著腳丫踩水玩,把褲子全弄濕了。我連忙找出拖把準備拖地。蘇珊從我手中搶過拖把交給托比,對他說:「把地拖幹,把濕衣服脫下來,自己洗乾淨。」托比不願意,又哭又鬧的,蘇珊二話不說,直接把他拉到貯藏室,關了禁閉。聽到托比在裡面發出驚天動地的哭喊,我心疼壞了,想進去把他抱出來。托比的外婆卻攔住我,說: 「這是蘇珊的事。」
過了一會兒,托比不哭了,他在貯藏室裡大聲喊:「媽媽,我錯了。」蘇珊站在門外,問:「那你知道該怎麼做了嗎?」 「我知道。 」蘇珊打開門,托比從貯藏室走出來,臉上還掛著兩行淚珠。他拿起有他兩個高的拖把吃力地把地上的水拖乾淨。然後,他脫下褲子,拎在手上,光著屁股走進洗手間,稀里嘩啦地洗起衣服來。
托比的外公外婆看著表情驚異的我,意味深長地笑了。這件事讓我感觸頗深。在很多中國家庭,父母管教孩子時,常常會引起「世界大戰」,往往是外婆外公護,爺爺奶奶攔! ! 夫妻吵架,雞飛狗跳。
後來,我和托比的外公外婆聊天時,提到這件事,托比的外公說了一段話,讓我印象深刻。他說,孩子是父母的孩子,首先要尊重父母對孩子的教育方式。孩子雖然小,卻是天生的外交家,當他看到家庭成員之間出現分歧時,他會很聰明地鑽空子。這不僅對改善他的行為毫無益處,反而會導致問題越來越嚴重,甚至帶來更多別的問題。而且,家庭成員之間發生衝突,不和諧的家庭氛圍會帶給孩子更多的不安全感,對孩子的心理髮展產生不利影響。所以,無論是父輩與祖輩在教育孩子的問題上發生分歧,還是夫妻兩人的教育觀念有差異,都不能在孩子麵前發生衝突。
托比的外公外婆在家裡住了一週,準備回加利福尼亞了。臨走前兩天,托比的外公鄭重地問女兒:「托比想要一輛玩具挖掘機,我可以買給他嗎?」蘇珊想了想,說:「你們這次來,已經送給他一雙旱冰鞋作為禮物了,到聖誕節時,再買玩具挖掘機當禮物送給他吧!」
我不知道托比的外公是怎麼告訴小傢伙的,後來我帶托比去超市,他指著玩具挖掘機說:「外公說,聖誕節時,給我買這個當禮物。」語氣裡滿是欣喜和期待。
雖然蘇珊對托比如此嚴格,托比卻對媽媽愛得不得了。他在外面玩時,會採集一些好看的小花或者他認為漂亮的葉子,鄭重其事地送給媽媽;別人送給他禮物,他會叫媽媽和他一起拆開;有什麼好吃的,也總要留一半給媽媽。
想到很多中國孩子對父母的漠視與冷淡,我不得不佩服我的洋媳婦。在我看來,在教育孩子的問題上,美國媽媽有很多值得中國媽媽學習的地方。
摘自:http://www.facebook.com/note.php?note_id=136147763071005&id=100000071367945
兒子去美國留學,畢業後定居美國。還給我找了個洋媳婦蘇珊。如今,小孫子托比已經3歲了。今年夏天,兒子為我申請了探親簽證。在美國待了三個月,洋媳婦蘇珊教育孩子的方法,令我這個中國婆婆大開眼界。
不吃飯就餓著
每天早上,托比醒來後,蘇珊把早餐往餐桌上一放,就自顧自地忙去了。托比會自己爬上凳子,喝牛奶,吃麵包片。吃飽後,他回自己的房間,在衣櫃裡找衣服、鞋子,再自己穿上。畢竟托比只有3歲,還搞不清楚子的正反面,分不清鞋子的左右腳。有一次托比又把褲子穿反了,我趕緊上前想幫他換,卻被蘇珊制止了。她說,如果他覺得不舒服,會自己脫下來,重新穿好;如果他沒覺得有什麼不舒服,那就隨他的便。那一整天,托比反穿著褲子跑來跑去,蘇姍像沒看見一樣。
又一會而,托比出去和鄰居家的小朋友玩,沒多久,氣喘吁吁地跑回家,對蘇珊說:「媽媽,露西說我的褲子穿反了,真的嗎?」露西是鄰居家的小姑娘,今年5 歲。蘇姍笑著說: 「是的,你要不要換回來?」托比點點頭,自己脫下褲子,仔細看了看,重新穿上了。從那以後,托比再也沒穿反過褲子。
我不禁想起,我的外孫女五六歲時不會用筷子,上小學時不會繫鞋帶。如今在上寄宿制初中的她,每個週末都要帶回家一大堆髒衣服呢。
一天中午,托比鬧情緒,不肯吃飯。蘇珊說了他幾句,憤怒地小托比一把將盤子推到了地上,盤子裡的食物灑了一地。蘇姍看著托比,認真地說:「看來你確實不想吃飯!記住,從現在到明天早上,你什麼都不能吃。」托比點點頭,堅定地回答:「Yes!」我在心裡暗笑,這母子倆,還都挺倔 !
下午,蘇珊和我商量,晚上由我做中國菜。我心領神會,托 比告別愛吃中國菜,一定是蘇珊覺得托比中午沒好好吃飯,想讓他晚上多吃點兒。
那天晚上我施展廚藝,做了托比最愛吃的糖醋裡脊、油悶大蝦,還用意大利麵做了中國式的涼麵。托比最喜歡吃那種涼麵,小小的人可以吃滿滿一大盤。
開始吃晚飯了,托比歡天喜地地爬上凳子。蘇珊卻走過來,拿走了他的盤子和刀叉,說:「我們已經約好了,今天你不能吃飯,你自己也答應了的。」托比看著面容嚴肅的媽媽,「哇」地一聲在哭起來,邊哭邊說:「媽媽,我餓,我要吃飯。」「不行,說過的話要算數。」蘇珊毫不心軟。
我心疼了,想替托比求情,說點好話,卻見兒子對我使眼色。想起我剛到美國時,兒子就跟我說,在美國,父母教育孩子時,別人千萬不要插手,即使是長輩也不例外。無奈,我! 只好保持沉默。
那頓飯,從始至終,可憐的小托比一直坐在玩具車裡,眼巴! 巴地看著我們三個大人狼吞虎嚥。我這才明白蘇珊讓我做中餐的真正用意。我相信,下一次,托比想發脾氣扔飯碗時,一定會想起自己餓著肚子看爸爸媽媽和奶奶享用美食的經歷。餓著肚子的滋味不好受,況且還是面對自己最喜愛的食物。
臨睡前,我和蘇珊一起去向托比道晚安。托比小心翼翼地問: 「媽媽,我很餓,現在我能吃中國面嗎?」蘇珊微笑著搖搖頭,堅決地說:「不!」托比嘆了口氣,又問:「那等我睡完覺睜開眼睛時,可以吃嗎?」「當然可以。」蘇珊溫柔地回答。托比甜甜地笑了。
大部分情況下,托比吃飯都很積極,他不想因為「罷吃」而錯過食物,再受餓肚子的苦。每當看到托比埋頭大口大口地! 吃飯,嘴上臉上粘的都是食物時,我就想起外孫女。她像托比這麼大時,為了哄她吃飯,幾個大人端著飯碗跟在她屁股後面跑,她還不買賬,還要談條件:吃完這碗買一個玩具,再吃一碗買一個玩具……
以其人之道,還治其人這身
有一天,我們帶托比去公園玩。很快,托比就和兩個女孩兒玩起了廚房遊戲。塑料小鍋、小鏟子、小盤子、小碗擺了一地。忽然,淘氣的托比拿起小鍋,使勁在一個女孩兒頭上敲了一下,女孩兒愣了一下,放聲大哭。另一個女孩兒年紀更小一些,見些情形,也被嚇得大哭起來。大概托比沒想到會有這麼嚴重的後果,站在一旁,愣住了。
蘇珊走上前,開清了事情的來龍去脈後,她一聲不吭,拿起小鍋,使勁敲到托比的頭上,托比沒防備,一下子跌坐在草地上,哇哇大哭起來。蘇珊問托比:「疼嗎?下次還這樣嗎?」 托比一邊哭,一邊拚命搖頭。? 說他以後再也不會這麼做了。
托比的舅舅送了他一輛淺藍色的小自行車,托比非常喜歡, 當成寶貝,不許別人碰。鄰居小姑娘露西是托比的好朋友,央求托比好幾次,要騎他的小車,托比都沒答應。
一次,幾個孩子一起玩時,露西趁托比不注意,偷偷騎上小車,揚長而去。托比發現後,氣憤地跑來向蘇珊告狀。蘇珊正和幾個孩子的母親一起聊天喝咖啡,便微笑著說:「你們的事情自己解決,媽媽可管不了。」托比無奈地走了。
過了一小會兒,露西騎著小車回來了。托比看到露西,一把將她推倒在地,搶過了小車。露西坐在地上大哭起來。蘇珊抱起露西,安撫了她一會兒。很快,露西就和別的小朋友興高采烈地玩了起來。
托比自己騎了會車,覺得有些無聊,看到那幾個孩子玩得那麼高興,他想加入,又覺得有些不好意思。他蹭到蘇珊身邊,嘟囔道:「媽媽,我想跟露西他們一起玩。」蘇珊不動聲色地說:「那你自己去找他們啦!」「媽媽,你陪我一起去。 」 托比懇求道。 「那可不行,剛才是你把露西弄哭的,現在你又想和大家玩,就得自己去解決問題。」
托比騎著小車慢慢靠近露西,快到她身邊時,又掉頭回來。來回好幾次,不知道從什麼時候開始,托比和露西又笑逐顏開,鬧成了一團。
管教孩子是父母的事
蘇珊的父母住在加利福尼亞州,聽說我來了,兩人開車來探望我們。家裡來了客人,托比很興奮,跑上跑下地亂竄。他把玩沙子用的小桶裝滿了水,提著小桶在屋裡四處轉悠。蘇珊警告了她好幾次,不要把水灑到地板上,托比置若罔聞。最後,托比還是把水桶弄倒了,水灑了一地。興奮的小托比不覺得自己做錯了事,還得意地光著腳丫踩水玩,把褲子全弄濕了。我連忙找出拖把準備拖地。蘇珊從我手中搶過拖把交給托比,對他說:「把地拖幹,把濕衣服脫下來,自己洗乾淨。」托比不願意,又哭又鬧的,蘇珊二話不說,直接把他拉到貯藏室,關了禁閉。聽到托比在裡面發出驚天動地的哭喊,我心疼壞了,想進去把他抱出來。托比的外婆卻攔住我,說: 「這是蘇珊的事。」
過了一會兒,托比不哭了,他在貯藏室裡大聲喊:「媽媽,我錯了。」蘇珊站在門外,問:「那你知道該怎麼做了嗎?」 「我知道。 」蘇珊打開門,托比從貯藏室走出來,臉上還掛著兩行淚珠。他拿起有他兩個高的拖把吃力地把地上的水拖乾淨。然後,他脫下褲子,拎在手上,光著屁股走進洗手間,稀里嘩啦地洗起衣服來。
托比的外公外婆看著表情驚異的我,意味深長地笑了。這件事讓我感觸頗深。在很多中國家庭,父母管教孩子時,常常會引起「世界大戰」,往往是外婆外公護,爺爺奶奶攔! ! 夫妻吵架,雞飛狗跳。
後來,我和托比的外公外婆聊天時,提到這件事,托比的外公說了一段話,讓我印象深刻。他說,孩子是父母的孩子,首先要尊重父母對孩子的教育方式。孩子雖然小,卻是天生的外交家,當他看到家庭成員之間出現分歧時,他會很聰明地鑽空子。這不僅對改善他的行為毫無益處,反而會導致問題越來越嚴重,甚至帶來更多別的問題。而且,家庭成員之間發生衝突,不和諧的家庭氛圍會帶給孩子更多的不安全感,對孩子的心理髮展產生不利影響。所以,無論是父輩與祖輩在教育孩子的問題上發生分歧,還是夫妻兩人的教育觀念有差異,都不能在孩子麵前發生衝突。
托比的外公外婆在家裡住了一週,準備回加利福尼亞了。臨走前兩天,托比的外公鄭重地問女兒:「托比想要一輛玩具挖掘機,我可以買給他嗎?」蘇珊想了想,說:「你們這次來,已經送給他一雙旱冰鞋作為禮物了,到聖誕節時,再買玩具挖掘機當禮物送給他吧!」
我不知道托比的外公是怎麼告訴小傢伙的,後來我帶托比去超市,他指著玩具挖掘機說:「外公說,聖誕節時,給我買這個當禮物。」語氣裡滿是欣喜和期待。
雖然蘇珊對托比如此嚴格,托比卻對媽媽愛得不得了。他在外面玩時,會採集一些好看的小花或者他認為漂亮的葉子,鄭重其事地送給媽媽;別人送給他禮物,他會叫媽媽和他一起拆開;有什麼好吃的,也總要留一半給媽媽。
想到很多中國孩子對父母的漠視與冷淡,我不得不佩服我的洋媳婦。在我看來,在教育孩子的問題上,美國媽媽有很多值得中國媽媽學習的地方。
摘自:http://www.facebook.com/note.php?note_id=136147763071005&id=100000071367945
訂閱:
文章 (Atom)
wibiya widget
搜尋Vegeee網誌
網站規劃,網頁製作,網站建置推薦
DesignPattern
我家寶貝
專案管理
投資理財網站
最新文章
最新回應
我常逛的網站
- JSFiddle
- Ruby on Rails 實戰聖經
- Badminton Technique
- PHPTalks
- GoodArticles
- Unicode編碼轉換器
- UI DesignPattern
- DynamicDrive
- 凡間
- 咕噜咕噜——告别异想天开的年代
- osc
- 網站推薦(大陸)
- Raie's Blog
- wowbox blog (網頁設計知識庫)
- 硬是要學!網路資源學習站
- 簡睿隨筆-科技篇
- Engadget 癮科技
- 軟體開發‧技巧篇
- PCDISCUSS論談
- OECSPACE
- CakePHP(英)
- cakebaker(英)
- CakePHP(繁)
- ericsk’s blog
- Ka-yue.com
- PHP程式學習筆記本
- 羽毛球好站介紹[圖文解說]
文章分類
- 工作方法 (2)
- 手機 (1)
- 台灣固網 (1)
- 正規表示法 (1)
- 生活 (4)
- 生活-勵志 (1)
- 羽球-技巧 (4)
- 羽球-其他 (1)
- 羽球-硬體 (3)
- 投資理財 (2)
- 其他 (8)
- 其它 (7)
- 育兒 (1)
- 科技-名詞解釋 (1)
- 基金-新聞 (1)
- 軟體-推薦 (1)
- 軟體推薦 (7)
- 程式-手冊 (1)
- 程式-名詞解釋 (5)
- 程式-安全 (2)
- 程式-CakePHP (10)
- 程式-HTML (4)
- 程式-JavaScript (47)
- 程式-jQuery (18)
- 程式-PEAR (1)
- 程式-PHP (106)
- 程式-ShellScript (1)
- 進修 (1)
- 演算法 (1)
- 網站介紹 (8)
- 網路 (10)
- 線上工具 (1)
- 養狗日記 (1)
- 勵志 (3)
- 瀏覽器-教學 (2)
- adware (1)
- Angile (2)
- angularjs (1)
- Apache-教學 (29)
- API (1)
- Appserv (1)
- AWS (1)
- BigData (2)
- Blogger-教學 (1)
- brew (1)
- C++ (2)
- composer (1)
- CruiseControl (1)
- CSS-教學 (10)
- Deployment (2)
- docker (1)
- doctrine (2)
- Dreamweaver-教學 (3)
- Eclipse-教學 (22)
- elastic-search (1)
- Email (1)
- FED (1)
- Fedora-教學 (1)
- FreeBSD-教學 (12)
- FreeBSD-Debug (2)
- git (12)
- heroku (8)
- homestead (2)
- HTML (1)
- HTML5 (2)
- ie (1)
- inno (1)
- IntelliJ IDEA (3)
- internet (1)
- Java (1)
- Joomla (2)
- JWT (1)
- kid (1)
- laravel (239)
- Linux-教學 (61)
- Mac (30)
- MailServer (1)
- mcrypt (1)
- MicrosoftOffice (1)
- Mobile (1)
- mockery (1)
- mootools (2)
- mysql (3)
- MySQL-教學 (18)
- MySQL-優化 (7)
- MySQL-Debug (12)
- n23 (1)
- nginx (1)
- nodejs (2)
- NoSQL (2)
- Oracle (1)
- PC-效能 (1)
- PC-病毒 (1)
- PC-硬體 (1)
- php (1)
- PHP-Wiki (1)
- PHPFramework (1)
- phpstorm (3)
- phpunit (2)
- postgreSQL (2)
- Propel (1)
- Python (7)
- Reac (1)
- React (12)
- React Native (1)
- react-n (1)
- react-native (1)
- react-saga (1)
- Redux (2)
- robocopy (1)
- RoR (2)
- security (3)
- Selenium (1)
- SEO-教學 (3)
- SeverTuning (12)
- Smarty-教學 (2)
- SQL Server (1)
- Sqlite (4)
- SSH (1)
- Subversion-教學 (16)
- Template (1)
- Testing (2)
- Tools (3)
- TWE-COMMERCE (1)
- VMWare (1)
- Vue.js (4)
- Vulnerability (1)
- Windows系統 (10)
- WordPress-教學 (6)
- Xampp (2)
- XenServer (3)
- xslt (1)
- ZendFramework (1)
網誌存檔
-
▼
2010
(184)
-
▼
10月
(12)
- SOLVING “FATAL ERROR: EXCEPTION THROWN WITHOUT A S...
- DIV圖層 被 Flash 覆蓋解決方式
- PHP code coverage implement
- 為什麼無法新增Zend Studio的external tool
- PHP: Traversing directories only
- A PHP library for unit testing non-public class me...
- SQLite Primary Key column not auto incrementing
- SQLite介紹
- PHP操作XML詳解
- PHPUnit + Aptana
- execute php.exe in PHP script
- 洋媳婦的教育方法...令中國婆婆大開眼界~
-
▼
10月
(12)