Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Wednesday, August 25, 2010

Writing MySQL Scripts with PHP and PDO

Writing MySQL Scripts with PHP and PDO

Paul DuBois
paul@kitebird.com

Document revision: 1.01
Last update: 2008-05-07

Table of Contents


PHP makes it easy to write scripts that access databases, enabling you to create dynamic web pages that incorporate database content. PHP includes several specialized database-access interfaces that take the form of separate sets of functions for each database system. There is one set for MySQL, another for InterBase, another for PostgreSQL, and so forth. However, having a different set of functions for each database makes PHP scripts non-portable at the lexical (source code) level. For example, the function for issuing an SQL statement is named mysql_query(), ibase_query(), or pg_exec(), depending on whether you are using MySQL, InterBase, or PostgreSQL.

In PHP 5 and up, you can avoid this problem by using the PHP Data Objects (PDO) extension. PDO supports database access in an engine-independent manner based on a two-level architecture:

  • The top level provides an interface that consists of a set of classes and methods that is the same for all database engines supported by PDO. The interface hides engine-specific details so that script writers need not think about which set of functions to use.
  • The lower level consists of individual drivers. Each driver supports a particular database engine and translates between the top-level interface seen by script writers and the database-specific interface required by the engine. This provides you the flexibility of using any database for which a driver exists, without having to consider driver-specific details.
This architectural approach has been used successfully with other languages--for example, to develop the DBI (Perl, Ruby), DB-API (Python), and JDBC (Java) database access interfaces. It's also been used with PHP before: PHPLIB, MetaBase, and PEAR DB are other packages that provide a uniform database-independent interface across different engines.

I have written elsewhere about using the PEAR DB module for writing PHP scripts that perform database processing in an engine-independent manner (see "Resources"). This document is similar but covers PDO instead. The examples use the driver for MySQL.

Preliminary Requirements


PDO uses object-oriented features available only in PHP 5 and up, so you must have PHP 5 or newer installed to use PDO for writing scripts that access MySQL.

PDO uses classes and objects to present an object-oriented interface. This article assumes that you are familiar with PHP's approach to object-oriented programming. If you are not, you may wish to review the "Classes and Objects" chapter of the PHP Manual.

Writing PDO Scripts


Scripts that use the PDO interface to access MySQL generally perform the following operations:

  • Connect to the MySQL server by calling new PDO() to obtain a database handle object.
  • Use the database handle to issue SQL statements or obtain statement handle objects.
  • Use the database and statement handles to retrieve information returned by the statements.
  • Disconnect from the server when the database handle is no longer needed.
The next sections discuss these operations in more detail.

Connecting to and Disconnecting from the MySQL Server


To establish a connection to a MySQL server, specify a data source name (DSN) containing connection parameters, and optionally the username and password of the MySQL account that you want to use. To connect to the MySQL server on the local host to access the test database with a username and password of testuser and testpass, the connection sequence looks like this:

   $dbh = new PDO("mysql:host=localhost;dbname=test", "testuser", "testpass");
For MySQL, the DSN is a string that indicates the database driver (mysql), and optionally the hostname where the server is running and the name of the database you want to use. Typical syntax for the DSN looks like this:
   mysql:host=host_name;dbname=db_name
The default host is localhost. No default database is selected if dbname is omitted.

The MySQL driver also recognizes port and unix_socket parameters, which specify the TCP/IP port number and Unix socket file pathname, respectively. If you use unix_socket, do not specify host or port.

For other database engines, the driver name is different (for example, pgsql for PostgreSQL) and the parameters following the colon might be different as well.

When you invoke the new PDO() constructor method to connect to your database server, PDO determines from the DSN which type of database engine you want to use and acesses the low-level driver appropriate for that engine. This is similar to the way that Perl or Ruby DBI scripts reference only the top-level DBI module; the connect() method provided by the top-level module looks at the DSN and determines which particular lower-level driver to use.

If new PDO() fails, PHP throws an exception. Otherwise, the constructor method returns an object of the PDO class. This object is a database handle that you use for interacting with the database server until you close the connection.

An alternative to putting the connection code directly in your script is to move it into a separate file that you reference from your main script. For example, you could create a file pdo_testdb_connect.php that looks like this:

     # pdo_testdb_connect.php - function for connecting to the "test" database

function testdb_connect ()
{
$dbh = new PDO("mysql:host=localhost;dbname=test", "testuser", "testpass");
return ($dbh);
}
?>
Then include the file into your main script and call testdb_connect() to connect and obtain the database handle:
   require_once "pdo_testdb_connect.php";

$dbh = testdb_connect ();
This approach makes it easier to use the same connection parameters in several different scripts without writing the values literally into every script; if you need to change a parameter sometime, just change pdo_testdb_connect.php. Use of a separate file also enables you to move the code that contains the connection parameters outside of the web server's document tree. That has the benefit of preventing it from being displayed literally if the server becomes misconfigured and starts serving PHP scripts as plain text.

Any of the PHP file-inclusion statements can be used, such as include or require, but require_once prevents errors from occurring if any other files that your script uses also reference pdo_testdb_connect.php.

When you're done using the connection, close it by setting the database handle to NULL:

   $dbh = NULL;
After that, $dbh becomes invalid as a database handle and can no longer be used as such.

If you do not close the connection explicitly, PHP does so when the script terminates.

While the database handle is open and you are using it to issue other PDO calls, you should arrange to handle errors if they occur. You can check for an error after each PDO call, or you can cause exceptions to be thrown. The latter approach is simpler because you need not check for errors explicitly; any error raises an exception that terminates your script. If you enable exceptions, you also have the option of catching them yourself instead of allowing them to terminate your script. By doing this, you can substitute your own error messages for the defaults, perform cleanup operations, and so on.

To enable exceptions, set the PDO error mode as follows after connecting:

   $dbh->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
That statement is something you could add to the testdb_connect() function if you want the error mode to be set automatically whenever you connect.

For more information on dealing with errors, see "Handling Errors."

Issuing Statements


After obtaining a database handle by calling new PDO(), you can use it to execute SQL statements:

  • For statements that modify rows and produce no result set, pass the statement string to the database handle exec() method, which executes the statement and returns an affected-rows count:
       $count = $dbh->exec ("some SQL statement");
  • For statements that select rows and produce a result set, invoke the database handle query() method, which executes the statement and returns an object of the PDOStatement class:
       $sth = $dbh->query ("some SQL statement");
    This object is a statement handle that provides access to the result set. It enables you to fetch the result set rows and obtain metadata about them, such as the number of columns.
To illustrate how to handle various types of statements, the following discussion shows how to create and populate a table using CREATE TABLE and INSERT (statements that return no result set). Then it uses SELECT to generate a result set.
Issuing Statements That Return No Result Set

The following code uses the database handle exec() method to issue a statement that creates a simple table animal with two columns, name and category:

   $dbh->exec ("CREATE TABLE animal (name CHAR(40), category CHAR(40))");
After the table has been created, it can be populated. The following example invokes the exec() method to issue an INSERT statement that loads a small data set into the animal table:
   $count = $dbh->exec ("INSERT INTO animal (name, category)
VALUES
('snake', 'reptile'),
('frog', 'amphibian'),
('tuna', 'fish'),
('racoon', 'mammal')");
exec() returns a count to indicate how many rows were affected by the statement. For the preceding INSERT statement, the affected-rows count is 4.
Issuing Statements That Return a Result Set

Now that the table exists and contains a few records, SELECT can be used to retrieve rows from it. To issue statements that return a result set, use the database handle query() method:

   $sth = $dbh->query ("SELECT name, category FROM animal");
printf ("Number of columns in result set: %d\n", $sth->columnCount ());
$count = 0;
while ($row = $sth->fetch ())
{
printf ("Name: %s, Category: %s\n", $row[0], $row[1]);
$count++;
}
printf ("Number of rows in result set: %d\n", $count);
A successful query() call returns a PDOStatement statement-handle object that is used for all operations on the result set. Some of the information available from a PDOStatement object includes the row contents and the number of columns in the result set:
  • The fetch() method returns each row in succession, or FALSE when there are no more rows.
  • The columnCount() methods returns the number of columns in the result set.
Note: A statement handle also has a rowCount() method, but it cannot be assumed to reliably return the number of rows in the result set. Instead, fetch the rows and count them, as shown in the preceding example.
Other Ways To Fetch Result Set Rows

fetch() accepts an optional fetch-mode argument indicating what type of value to return. This section describes some common mode values. Assume in each case that the following query has just been issued to produce a result set:

   $sth = $dbh->query ("SELECT name, category FROM animal");
  • PDO::FETCH_NUM
    Return each row of the result set as an array containing elements that correspond to the columns named in the SELECT statement and that are accessed by numeric indices beginning at 0:
       while ($row = $sth->fetch (PDO::FETCH_NUM))
    printf ("Name: %s, Category: %s\n", $row[0], $row[1]);
  • PDO::FETCH_ASSOC
    Return each row as an array containing elements that are accessed by column name:
       while ($row = $sth->fetch (PDO::FETCH_ASSOC))
    printf ("Name: %s, Category: %s\n", $row["name"], $row["category"]);
  • PDO::FETCH_BOTH
    Return each row as an array containing elements that can be accessed either by numeric index or by column name:
       while ($row = $sth->fetch (PDO::FETCH_BOTH))
    {
    printf ("Name: %s, Category: %s\n", $row[0], $row[1]);
    printf ("Name: %s, Category: %s\n", $row["name"], $row["category"]);
    }
  • PDO::FETCH_OBJ
    Return each row as an object. In this case, you access column values as object properties that have the same names as columns in the result set:
       while ($row = $sth->fetch (PDO::FETCH_OBJ))
    printf ("Name: %s, Category: %s\n", $row->name, $row->category);
If you invoke fetch() with no argument, the default fetch mode is PDO::FETCH_BOTH unless you change the default before fetching the rows:
  • The query() method accepts an optional fetch-mode argument following the statement string:
       $sth = $dbh->query ("SELECT name, category FROM animal", PDO::FETCH_OBJ);
    while ($row = $sth->fetch ())
    printf ("Name: %s, Category: %s\n", $row->name, $row->category);
  • Statement handles have a setFetchMode() method to set the mode for subsequent fetch() calls:
       $sth->setFetchMode (PDO::FETCH_OBJ);
    while ($row = $sth->fetch ())
    printf ("Name: %s, Category: %s\n", $row->name, $row->category);
Another way to fetch results is to bind variables to the result set columns with bindColumn(). Then you fetch each row using the PDO::FETCH_BOUND fetch mode. PDO stores the column values in the variables, and fetch() returns TRUE instead of a row value while rows remain in the result set:
   $sth = $dbh->query ("SELECT name, category FROM animal");
$sth->bindColumn (1, $name);
$sth->bindColumn (2, $category);
while ($sth->fetch (PDO::FETCH_BOUND))
printf ("Name: %s, Category: %s\n", $name, $category);

Using Prepared Statements


exec() and query() are PDO object methods: You use them with a database handle and they execute a statement immediately and return its result. It is also possible to prepare a statement for execution without executing it immediately. The prepare() method takes an SQL statement as its argument and returns a PDOStatement statement-handle object. The statement handle has an execute() method that executes the statement:

   $sth = $dbh->prepare ($stmt);
$sth->execute ();
Following execution, other statement-handle methods provide information about the statement result:
  • For a statement that modifies rows, invoke rowCount() to get the rows-affected count:
       $sth = $dbh->prepare ("DELETE FROM animal WHERE category = 'mammal'");
    $sth->execute ();
    printf ("Number of rows affected: %d\n", $sth->rowCount ());
  • For a statement that produces a result set, the fetch() method retrieves them and the columnCount() method indicates how many columns there are. To determine how many rows there are, count them as you fetch them. (As mentioned previously, rowCount() returns a row count, but should be used only for statements that modify rows.)
       $sth = $dbh->prepare ("SELECT name, category FROM animal");
    $sth->execute ();
    printf ("Number of columns in result set: %d\n", $sth->columnCount ());
    $count = 0;
    while ($row = $sth->fetch ())
    {
    printf ("Name: %s, Category: %s\n", $row[0], $row[1]);
    $count++;
    }
    printf ("Number of rows in result set: %d\n", $count);
If you are not sure whether a given SQL statement modifies or returns nows, the statement handle itself enables you to determine the proper mode of processing. See "Determining the Type of a Statement."

As just shown, prepared statements appear to offer no advantage over exec() and query() because using them introduces an extra step into statement processing. But there are indeed some benefits to them:

  • Prepared statements can be parameterized with placeholders that indicate where data values should appear. You can bind specific values to these placeholders and PDO takes care of any quoting or escaping issues for values that contain special characters. "Placeholders and Quoting" discusses these topics further.
  • Separating statement preparation from execution can be more efficient for statements to be executed multiple times because the preparation phase need be done only once. For example, if you need to insert a bunch of rows, you can prepare an INSERT statement once and then execute it repeatedly, binding successive row values to it for each execution.

Placeholders and Quoting


A prepared statement can contain placeholders to indicate where data values should appear. After you prepare the statement, bind specific values to the placeholders (either before or at statement-execution time), and PDO substitutes the values into the statement before sending it to the database server.

PDO supports named and positional placeholders:

  • A named placeholder consists of a name preceded by a colon. After you prepare the statement, use bindValue() to provide a value for each placeholder, and then execute the statement. To insert another row, bind new values to the placeholders and invoke execute() again:
       $sth = $dbh->prepare ("INSERT INTO animal (name, category)
    VALUES (:name, :cat)");
    $sth->bindValue (":name", "ant");
    $sth->bindValue (":cat", "insect");
    $sth->execute ();
    $sth->bindValue (":name", "snail");
    $sth->bindValue (":cat", "gastropod");
    $sth->execute ();
    As an alternative to binding the data values before calling execute(), you can pass the values directly to execute() using an array that associates placeholder names with the values:
       $sth->execute (array (":name" => "black widow", ":cat" => "spider"));
  • Positional placeholders are characters within the statement string. You can bind the values prior to calling execute(), similar to the previous example, or pass an array of values directly to execute():
       $sth = $dbh->prepare ("INSERT INTO animal (name, category)
    VALUES (?, ?)");
    # use bindValue() to bind data values
    $sth->bindValue (1, "ant");
    $sth->bindValue (2, "insect");
    $sth->execute ();
    # pass values directly to execute() as an array
    $sth->execute (array ("snail", "gastropod"));
Positional placeholder numbers begin with 1.

An alternative to bindValue() is bindParam(), which adds a level of indirection to value-binding. Instead of passing a data value as the second argument to bindParam(), pass a variable to associate the variable with the placeholder. To supply a value for the placeholder, assign a value to the variable:

   $sth = $dbh->prepare ("INSERT INTO animal (name, category)
VALUES (?, ?)");
$sth->bindParam (1, $name);
$sth->bindParam (2, $category);
$name = "ant";
$category = "insect";
$sth->execute ();
$name = "snail";
$category = "gastropod";
$sth->execute ();
The preceding examples use INSERT statements, but placeholder techniques are applicable to any type of statement, such as UPDATE or SELECT.

One of the benefits of using placeholders is that PDO handles any quoting or escaping of special characters or NULL values. For example, if you bind the string "a'b'c" to a placeholder, PDO inserts "'a\'b\'c'" into the statement. To bind the SQL NULL value to a placeholder, bind the PHP NULL value. In this case, PDO inserts the word "NULL" into the statement without surrounding quotes. (Were quotes to be added, the value inserted into the statement would be the string "'NULL'", which is incorrect.)

PDO also provides a database handle quote() method to which you can pass a string and receive back a quoted string with special characters escaped. However, I find this method deficient. For example, if you pass it NULL, it returns an empty string, which if inserted into a statement string does not correspond to the SQL NULL value. Use quote() with care if you use it.

Determining the Type of a Statement


When you issue a statement using a database handle, you must know whether the statement modifies rows or produces a result set, so that you can invoke whichever of exec() or query() is appropriate. However, under certain circumstances, you might not know the statement type, such as when you write a script to execute arbitrary statements that it reads from a file. To handle such cases, use prepare() with the database handle to get a statement handle and execute() to execute the statement. Then check the statement's column count:

  • If columnCount() is zero, the statement did not produce a result set. Instead, it modified rows and you can invoke rowCount() to determine the number of affected rows.
  • If columnCount() is greater than zero, the statement produced a result set and you can fetch the rows. To determine how many rows there are, count them as you fetch them.
The following example determines whether a statement modifies rows or produces a result set, and then processes it accordingly:
   $sth = $dbh->prepare ($stmt);
$sth->execute ();
if ($sth->columnCount () == 0)
{
# there is no result set, so the statement modifies rows
printf ("Number of rows affected: %d\n", $sth->rowCount ());
}
else
{
# there is a result set
printf ("Number of columns in result set: %d\n", $sth->columnCount ());
$count = 0;
while ($row = $sth->fetch (PDO::FETCH_NUM))
{
# display column values separated by commas
print (join (", ", $row) . "\n");
$count++;
}
printf ("Number of rows in result set: %d\n", $count);
}

Handling Errors


When you invoke new PDO() to create a database handle, occurrance of an error causes a PDOException to be thrown. If you don't catch the exception, PHP terminates your script. To handle the exception yourself, use a try block to perform the connection attempt and a catch block to catch any error that occurs:

   try
{
$dbh = new PDO("mysql:host=localhost;dbname=test", "testuser", "testpass");
}
catch (PDOException $e)
{
print ("Could not connect to server.\n");
print ("getMessage(): " . $e->getMessage () . "\n");
}
A PDOException is an extension of the PHP Exception class, so it has getCode() and getMessage() methods that return an error code and descriptive message, respectively. (However, I find that getCode() always returns 0 for connection errors and is meaningful only for PDO exceptions that occur after the connection has been established.)

After you successfully obtain a database handle, further PDO calls that use it are handled according to the PDO error mode. There are three modes:

  • PDO::ERRMODE_SILENT
    When an error occurs in silent or warning mode for a given object method, PDO sets up error information that you can access when the method returns. This is the default error mode.
  • PDO::ERRMODE_WARNING
    This is like silent mode but PDO also displays a warning message in addition to setting up error information when an error occurs.
  • PDO::ERRMODE_EXCEPTION
    PDO sets up error information when an error occurs and throws a PDOException.
PDO sets error information for the object to which the error applies, regardless of the error mode. This information is available via the object's errorCode() and errorInfo() methods. errorCode() returns an SQLSTATE value (a five-character string). errorInfo() returns a three-element array containing the SQLSTATE value, and a driver-specific error code and error message. For MySQL, the driver-specific values are a numeric error code and a descriptive error message.

To handle errors in silent mode, you must check the result of each PDO call. The following example shows how to test for errors during an operation that uses a database handle, $dbh, and a statement handle, $sth (you would not necessarily print all the available information as the example does):

   if (!($sth = $dbh->prepare ("INSERT INTO no_such_table")))
{
print ("Could not prepare statement.\n");
print ("errorCode: " . $dbh->errorCode () . "\n");
print ("errorInfo: " . join (", ", $dbh->errorInfo ()) . "\n");
}
else if (!$sth->execute ())
{
print ("Could not execute statement.\n");
print ("errorCode: " . $sth->errorCode () . "\n");
print ("errorInfo: " . join (", ", $sth->errorInfo ()) . "\n");
}
Testing the result of every call can become messy quickly. Another way to deal with failures is to set the error handling mode so that any error raises an exception:
   $dbh->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
In this case, you can assume that if you invoke a method and it returns, it succeeded. You can either leave exceptions uncaught or catch and handle them yourself. If you leave them uncaught, exceptions cause PHP to print a backtrace and terminate your script. To catch exceptions, perform PDO operations using a try/catch construct. The try block contains the operations and the catch block handles an execption if one occurs.
   try
{
$sth = $dbh->prepare ("INSERT INTO no_such_table");
$sth->execute ();
}
catch (PDOException $e)
{
print ("The statement failed.\n");
print ("getCode: ". $e->getCode () . "\n");
print ("getMessage: ". $e->getMessage () . "\n");
}
By using try and catch, you can substitute your own error messages if you like, perform cleanup operations, and so on.

As shown in the preceding example, the try block can contain operations on multiple handles. However, if an exception occurs in that case, you won't be able to use the handle-specific errorCode() or errorInfo() methods in the catch block very easily because you won't know which handle caused the error. You'll need to use the information available from the exception methods, as shown.

Using Transactions


In MySQL, some storage engines are transactional, which enables you to perform an operation and then commit it permanently if it succeeded or roll it back to cancel its effects if an error occurred. PDO provides a mechanism for performing transactions that is based on the following database-handle methods:

  • To start a transaction, invoke beginTransaction() to disable autocommit mode so that database changes do not take effect immediately.
  • To commit a successful transaction or roll back an unsuccessful one, invoke commit() or rollback(), respectively.
The easiest way to use these methods is to enable PDO exceptions and use try and catch to handle errors:
   $dbh->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try
{
$dbh->beginTransaction (); # start the transaction
# ... perform database operation ...
$dbh->commit (); # success
}
catch (PDOException $e)
{
print ("Transaction failed: " . $e->getMessage () . "\n");
$dbh->rollback (); # failure
}
For additional paranoia, you can place the rollback() call within a nested try/catch construct so that if rollback() itself fails and raises another exception, the script doesn't get terminated.

Resources


Revision History


  • 1.00--Original version.
  • 1.01, 2008-05-07--Removed my mistaken statement that the PDO driver for MySQL requires the mysqli extension. It does not. The driver uses libmysqlclient directly.

Tuesday, November 3, 2009

PHP - Giới thiệu - Sơ lược về ngôn ngữ PHP

MỤC LỤC

Trở về đầu trang


CÚ PHÁP CĂN BẢN

Trang PHP là 1 trang HTML có nhúng mã PHP
Để minh hoạ cho điều này, ta hãy xem qua một số ví dụ sau:

Ví dụ 1: lưu file sau lên đĩa với tên vd1.php và chạy thử:

<html><head><title>Testing page</title></head>
<body><?php echo "Hello, world!"; ?></body>
</html>
Bạn sẽ nhận được 1 trang HTML mà khi view source bạn xẽ nhận được nội dung như sau:
<html><head><title>Testing page</title></head>
<body>Hello, World!</body>
</html>

Ví dụ 2: lưu file sau lên đĩa với tên vd2.php và chạy thử:

<?php echo "<html><head><title>Testing page</title></head>
<body>Hello, world!</body>
</html>"
; ?>
Bạn cũng nhận được 1 trang HTML có source là:
<html><head><title>Testing page</title></head>
<body>Hello, World!</body>
</html>

Như vậy có thể nhận xét rằng 1 trang PHP cũng chính là 1 trang HTML có nhúng mã PHP ở bên trong và có phần mở rộng là .php. Phần mã PHP được đặt trong thẻ mở <?php và thẻ đóng ?>. Khi trình duyệt truy cập vào 1 trang PHP, server sẽ đọc nội dung file PHP lên, lọc ra các đoạn mã PHP, thực thi các đoạn mã đó, lấy kết quả xuất ra của các đoạn mã PHP thay thế vào chỗ ban đầu của chúng trong file PHP, cuối cùng server trả về kết quả cuối cùng là 1 trang nội dung HTML về cho trình duyệt.
Ở ví dụ 1 bên trên, server thực thi đoạn mã <?php echo "Hello, world!"; ?>, đoạn mã này sẽ xuất ra dòng chữ Hello, world!, dòng chữ này sẽ được server thay thế ngược lại vào vị trí của đoạn mã PHP và trả về kết quả cuối cùng cho trình duyệt:

<html><head><title>Testing page</title></head>
<body>Hello, World!</body>
</html>

Như vậy thì ta hoàn toàn có thể tạo ra 1 file vd3.php với nội dung như sau:

<html><head><title>Testing page</title></head>
<body>Hello, World!</body>
</html>
Và file này vẫn chạy được ngon lành, không có vấn đề gì hết!

Lệnh echo dùng để xuất 1 chuỗi văn bản về trình duyệt
Ở các ví dụ bên trên, ta đã dùng 1 lệnh của PHP là lệnh echo. Lệnh này dùng để xuất 1 chuỗi văn bản về cho trình duyệt.

Ví dụ câu lệnh echo "Hello, world!"; trình duyệt sẽ nhận được chỗi văn bản Hello, world!.
Câu lệnh echo 1+2; sẽ trả về cho trình duyệt chỗi văn bản 3.
Và câu lệnh echo 1+2, "Hello, world!"; sẽ trả về trình duyệt chỗi 3Hello, world!.

Phân cách các lệnh bằng dấu chấm phảy (;)
Tương tự như các ngôn ngữ lập trình C hoặc Pascal, 1 câu lệnh của PHP được kết thúc bằng dấu chấm phảy (;). Ví dụ:
echo 1+2;
echo "Hello, world!";

Chú thích trong chương trình
Các chú thích không phải là mã chương trình, nhưng nó giúp ta ghi chú về 1 đoạn chương trình nào đó. Khi lập trình, bạn nên để các ghi chú vào trong chương trình để sau này khi đọc lại code, bạn sẽ nhanh chóng nắm bắt được nội dung và ý nghĩa của đoạn chương trình đã biết.
PHP cho phép ta ghi 2 loại chú thích: chú thích trên 1 dòng (chú thích loại này chỉ có thể ghi trên 1 dòng mà thôi), và chú thích nhiều dòng (chú thích loại này có thể ghi dài bao nhiêu cũng được).
Chú thích 1 dòng được bắt đầu bằng // hoặc #, và những gì được ghi từ đó về sau là chú thích. Chú thích nhiều dòng được bắt đầu bằng /* và kết thúc bằng */, những gì ở giữa là chú thích. Ví dụ:

<?php
//Đây là chú thích 1 dòng, đoạn chương trình sau sẽ in ra chuỗi 123
echo 123;

#Đây cũng là chú thích 1 dòng, đoạn chương trình sau sẽ in ra chuỗi abc
echo "abc";

/*
Đây là chú thích nhiều dòng
Đoạn chương trình sau sẽ in ra chuỗi abc123
*/

echo "abc123";
?>


KIỂU DỮ LIỆU

PHP hỗ trợ 8 kiểu dữ liệu chính:

  • 4 kiểu dữ liệu vô hướng: boolean, integer, float (double), string.
  • 2 kiểu dữ liệu tổ hợp: array, object.
  • 2 kiểu dữ liệu đặt biệc: resource, NULL.

Kiểu Boolean
Kiểu boolean mang 1 trong 2 giá trị TRUE (đúng) hoặc FALSE (sai). Ví dụ:

<?php
$a = TRUE;
$b = FALSE;

//phép toán == kiểm tra xem 2 biểu thức có giá trị bằng nhau hay không
$c = (1==2); //vì 1 khác 2 nên $c mang giá trị FALSE
$d = ("abc" == "def"); //$d mang giá trị TRUE
?>

"Ép" kiểu sang boolean: một số giá trị được chuyển đổi thành FALSE trong các biểu thức boolean nếu như giá trị đó là:

  • số nguyên 0,
  • số thực 0.0,
  • chuỗi rỗng "", hoặc chuỗi "0",
  • mảng rỗng (không chứa phần tử nào) Array(),
  • đối tượng không chứa phần tử nào (chỉ đúng với PHP4),
  • giá trị NULL
Các giá trị còn lại sẽ được chuyển đổi thành TRUE.

Kiểu Integer
Kiểu integer mang các giá trị số nguyên ..., -2, -1, 0, 1, 2, ...Trên hầu hết các hệ thống, kiểu số nguyên có kích thước 32 bit, mang giá trị từ -2147483647 cho đến 2147483648. Ví dụ:

<?php
$a = 1234;
$b = -123;
$c = 0123; //giá trị 123 ở hệ cơ số 8, tương đương với 83 ở hệ cơ số 10
$d = 0x1F; //giá trị 1F ở hệ cơ số 16, tương đương với 31 ở hệ cơ số 10
?>

Kiểu Float (Double)
Kiểu float (hoặc double) là kiểu số thực, có thể mang bất cứ giá trị số thực nào. Trên hầu hết các hệ thống, kiểu số thực có kích thước 64 bit. Ví dụ:

<?php
$a = 1.234;
$b = 1.2e3; //= 1.2*10^3 = 1200
$c = 7E-10; //= 7*(10^-10) = 0.0000000007
$d = -1.23;
?>

Kiểu String
Kiểu string lưu giữ 1 chuỗi ký tự, mỗi ký tự có kích thước 1 byte. Nội dung string được đặt giữa 2 dấu nháy, nháy đơn (') hoặc nháy kép ("). Ví dụ

<?php
$a = 'Đây là 1 chuỗi được đặt giữa dấu nháy đơn';
$b = "Đây là 1 chuỗi được đặt giữa dấu nháy kép";
$c = 'Đây là 1 chuỗi được đặt giữa dấu nháy đơn với "vài dấu nháy kép ở giữa"';
$d = "Đây là 1 chuỗi được đặt giữa dấu nháy kép với 'vài dấu nháy đơn ở giữa'";
?>
Nếu bạn muốn sử dụng dấu nháy đơn ở trong 1 chuỗi được bọc bởi dấu nháy đơn, hoặc sử dụng dấu nháy kép đặt giữa chuỗi được bọc bởi dấu nháy kép thì bạn để thêm ký tự \ (gọi là ký tự escape) ở phía trước. Ví dụ:
<?php
$a = 'Dấu \'nháy đơn\' ở giữa chuỗi'; //$a mang giá trị: Dấu 'nháy đơn' ở giữa chuỗi
$b = "Dấu \"nháy kép\" ở giữa chuỗi"; //$b mang giá trị: Dấu "nháy kép" ở giữa chuỗi
$c = "Dùng ký tự \\ ở giữa câu \\ thì sao?"; //$c mang giá trị: Dùng ký tự \ ở giữa câu \ thì sao?
?>
Khi sử dụng dấu nháy đôi để bọc chuỗi, ngoài \', \"\\, PHP có thể nhận dạng thêm một số chuỗi ký tự escape đặt biệc nữa:
  • \n: ký tự xuống hàng LF (ký tự có mã 10 trong bảng mã ASCII)
  • \r: ký tự về đầu dòng CR (ký tự có mã 13 trong bảng mã ASCII)
  • \t: ký tự tab (ký tự có mã 9 trong bảng mã ASCII)
  • \$: ký tự $
  • \ooo: (với o là 1 chữ số từ 0 đến 7) biểu thị 1 ký tự có mã ASCII ooo trong hệ cơ số 8.
    Ví dụ \101 sẽ là ký tự 'A' (101 trong hệ cơ số 8 tương đương 65 trong hệ cơ số 10, ký tự ASCII có mã 65 chính là ký tự 'A').
  • \xhh: (với h là 1 chữ số từ 0 đến 9 hoặc 1 chữ cái từ A tời F) biểu thị 1 ký tự có mã ASCII hh trong hệ cơ số 16.
    Ví dụ \0x41 sẽ là ký tự 'A' (41 trong hệ cơ số 16 chính là 65 trong hệ cơ số 10).

Ngoài ra, nếu bạn để 1 biến vào giữa 1 chuỗi được bọc với dấu nháy kép, giá trị của biến sẽ được thay thế vào trong chuỗi. ví dụ:

<?php
$a = 1;
$b = 2;
$c = 3;
$d = "$a $b $c"; //$d sẽ mang giá trị là chuỗi "1 2 3"
?>

Kiểu Array
Array là một mảng gòm nhiều phần tử. Array được tạo qua lệnh Array. Ví dụ:

<?php
$a = Array(1,2,3);
Lúc này $a sẽ là 1 mảng gồm 3 phần tử số nguyên là 1, 23

Các phần tử trong mảng $a được tạo ở trên sẽ được đánh số thứ tự từ 0, 1 cho đến 2
Để truy cập tới từng phần tử của $a
echo $a[0]; //in ra giá trị 1
echo $a[2]; //in ra giá trị 3

$a[1] = 5; //giờ đây $a = Array(1,5,3)
?>
Mảng còn có thể được tạo thành bởi các cặp (khoá, giá trị). Ví dụ:
<?php
$a = Array(
"khoá 1" => "giá trị 1",
"khoá 2" => "giá trị 2",
"khoá 3" => "giá trị 3"
);
echo $a["khoá 1"]; //in ra: giá trị 1

$b = Array(
"a" => "Nguyễn",
"b" => "Bá",
"c" => "Thành"
);
echo $b["a"]; //in ra: Nguyễn

$b["a"] = "Nguyen";
$b["b"] = "Ba";
$b["c"] = "Thanh";
//giờ đây $b = Array("a" => "Nguyen", "b" => "Ba", "c" => "Thanh")
?>

Kiểu Object
Kiểu object (đối tượng) lưu giữ 1 bản thể (instance) của 1 lớp (class). Ta sẽ tìm kiểu kỹ thêm về kiểu object trong phần Lập trình hướng đối tượng với PHP.

Kiểu Resource
Kiểu resource (tài nguyên) được sử dụng bởi các hàm đặt biệc của PHP (ví dụ hàm mysql_connect sẽ trả về kiểu resource). Ta sẽ tìm hiểu kỹ hơn về kiểu resource trong các bài viết khác.

Kiểu NULL
Đây là 1 giá trị đặt biệc, báo cho PHP biết rằng 1 biến nào đó chưa/không mang giá trị nào cả. Ví dụ:

<?php
$a = 1; //$a mang giá trị 1

$a = NULL; //bây giờ $a không mang giá trị nào cả

$a = 2; //giờ đây $a mang giá trị 2

//hàm unset sẽ làm cho 1 biến có giá trị là NULL
unset($a); //giừo $a lại là NULL
?>



BIẾN

Có lẽ hơi muộn khi tới tận bây giờ ta mới tìm hiểu tới biến trong PHP. Một biến trong PHP được bắt đầu bằng ký tự $ và đi theo ngay sau đó là tên của biến. Ví dụ:
$a: biến có tên là a
$abc123: biến có tên là abc123

Tuy nhiên vẫn còn nhiều điều thú vị về biến đang chờ ta khám phá.

  • Biến trong PHP phân biệt chữ hoa và chữ thường. Tức $Abc và $abc là 2 biến hoàn toàn khác nhau.
  • Tên biến chỉ được bao gồm các ký tự chữ cái (a..z hoặc A...Z), chữ số (0...9) và ký tự gạch dưới (_); nhưng tên biến không được bắt đầu bằng ký tự gạch dưới hoặc chữ số. Các tên biến sau là không hợp lệ!
    $_abc Không hợp lệ! bắt đầu bằng ký tự gạch dưới
    $1abc Không hợp lệ! bắt đầu bằng chữ số
    $nguyễn Không hợp lệ! tên biến có ký tự đặt biệc (ễ)

Tầm vực (scope) của biến
Tầm vực của biến là ngữ cảnh mà ở trong đó biến được định nghĩa. Ví dụ:

<?php
$a = 1; //tầm vực của biến $a bắt đầu từ đây

include 'b.php'; trải dài tới bên trong file b.php

//tới cuối file vẫn còn hợp lệ
?>

Tuy nhiên khi gặp 1 hàm do người dùng định nghĩa, bên trong hàm, biến cục bộ sẽ được dùng thay vì biến toàn cục. Ví dụ:

<?php
$a = 1; //biến toàn cục

//hàm do tự tạo
function test() {
echo $a;
} //end test
?>
Ở ví dụ trên, câu lệnh echo $a sẽ không in ra giá trị nào hết vì câu lệnh này nằm bên trong hàm test nên $a ở đây được hiểu là biến cục bộ $a của hàm (mà hàm này ta chưa khai báo biến cục bộ nào cả).

Để truy cập tới các biến toàn cục ở bên trong 1 hàm do người dùng định nghĩa, ta có thể dùng 1 trong 2 cách sau: Cách 1:

<?php
$a = 1; //biến toàn cục

//hàm do tự tạo
function test() {
//từ khoá global báo cho php biết là bên trong hàm test
//bây giờ ta sẽ dùng biến toàn cục $a
global $a;

echo $a; //in ra giá trị: 1
} //end test
?>
Cách 2:
<?php
$a = 1; //biến toàn cục

//hàm do tự tạo
function test() {
echo $GLOBALS['a']; //in ra giá trị: 1
} //end test
?>



BIỂU THỨC

Biểu thức là nền tảng quan trọng của PHP. Hầu như mọi thứ bạn ghi trong file php đều là biểu thức. Nói một cách đơn giản, bất cứ cái gì mang 1 giá trị nào đó đều có thể là 1 biểu thức. Ta xét câu lệnh đơn giản sau:
$a = 5;
Ở đây 5 là một biểu thức, kết của của biểu thức này là giá trị 5, và kết quả này được gán cho biến $a. $b = $a;
Ở đây $a lại là 1 biểu thức, giá trị của $a được gán cho biến $b.

Biểu thức trong PHP có thể phức tạp hơn thế, ví dụ:
$a = 1;
$b = 2;
$c = 3;
$d = $a + $b + $c;



TOÁN TỬ

Toán tử kết hợp các giá trị hoặc biểu thức lại với nhau và tạo ra một giá trị mới. Ví dụ trong biểu thức 1+2 thì + là toán tử kết hợp hai giá trị 1 và 2 lại với nhau tạo ra giá trị mới là 3.

Các toán tử trong PHP được chia thành 3 nhóm:

  • Các toán tử áp dụng trên 1 giá trị, ví dụ như toán tử ++ hoặc --
  • Các toán tử kết hợp 2 hoặc nhiều giá trị, ví dụ như toán tử +, -, *, /
  • Toán tử ?: dùng để chọn 1 trong 2 giá trị tuỳ thuộc vào 1 điều kiện cho trước

Thứ tự ưu tiên của toán tử
Các toán tử khác nhau có thể có độ ưu tiên khác nhau. Trong cùng 1 biểu thức có nhiều toán tử, toán tử nào có độ ưu tiên cao hơn sẽ được thực hiện trước (trừ khi bạn nhóm các biểu thức lại bằng dấu ngoặc () ). Nếu trong biểu thức có 2 toán tử có cùng độ ưu tiên thì qui tắc liên kết của từng toán tử sẽ qui định thứ tự thực hiện của các toán tử đó.
Sau đây là bảng liệt kê các toán tử cùng thứ tự ưu tiên của chúng (toán tử có độ ưu tiên cao hơn được liệt kê bên trên, các toán tử có độ ưu tiên thấp hơn được lệt kê bên dưới).

Qui tắc liên kết Toán tử Ghi chú
new Tạo 1 đối tượng từ 1 class, toán tử này chỉ áp dụng trên 1 toán hạng nên không có qui tắc liên kết
Bên phải trước [ Toán tử truy cập 1 phần tử trong mảng
++ -- Tăng/Giảm 1 đơn vị, toán tử này chỉ áp dụng trên 1 toán hạng nên không có qui tắc liên kết
! ~ - (int) (float) (string) (array) (object) @ Các toán tử này chỉ áp dụng trên 1 toán hạng nên không có qui tắc liên kết
Bên trái trước * / %
Bên trái trước + - .
Bên trái trước << >>
== != === !=== Toán tử so sánh, chỉ áp dụng trên 2 toán hạng nên không có qui tắc liên kết
Bên trái trước &
Bên trái trước ^
Bên trái trước |
Bên trái trước &&
Bên trái trước ||
Bên trái trước ? :
Bên phải trước = += -= *= /= .= %= &= |= ^= <<= >>=
Bên trái trước and
Bên trái trước xor
Bên trái trước or
Bên trái trước ,



CÁC CÂU LỆNH ĐIỂU KHIỂN

Câu lệnh if
Cú pháp đơn giản nhất của câu lệnh if có dạng như sau:

if ( biểu thức )
câu lệnh;
Câu lệnh if trên được diễn giải như sau: nếu biểu thức trả về giá trị TRUE (hoặc tương đương với TRUE sau khi chuyển đổi) thì câu lệnh sẽ được thực thi; ngược lại (khi biểu thức trả về giá trị FALSE) thì bỏ qua không thực thi câu lệnh nữa.

Cú pháp nâng cao của câu lệnh if có dạng như sau:

if ( biểu thức )
câu lệnh 1;
else
câu lệnh 2;
Câu lệnh if trên được diễn giải như sau: nếu biểu thức trả về giá trị TRUE thì câu lệnh 1 sẽ được thi hành, ngược lại thì câu lệnh 2 sẽ được thi hành.

Các lệnh if có thể được lồng vào nhau để tạo ra câu lệnh if phức tạp hơn:

if ( biểu thức 1 )
if ( biểu thức 2 )
câu lệnh 1;
else
câu lệnh 2;
else
câu lệnh 3;
Nếu biểu thức 1 trả về giá trị FALSE thì câu lệnh 3 sẽ được thực hiện, ngược lại xét tiếp biểu thức 2: nếu biểu thức 2 trả về giá trị TRUE thì thực hiện câu lệnh 1, ngược lại nếu biểu thức 2 trả về giá trị FALSE thì thực hiện câu lệnh 2.
if ( biểu thức 1 )
câu lệnh 1;
else if ( biểu thức 2 )
câu lệnh 2;
else if ( biểu thức 3 )
câu lệnh 3;
else
câu lệnh 4;
Nếu biểu thức 1 trả về TRUE thì thực hiện câu lệnh 1 (các câu lệnh 2,3,4 không thực hiện), nếu biểu thức 1 trả về FALSE và biểu thức 2 trả về TRUE thì câu lệnh 2 được thực hiện, nếu biểu thức 1 trả về FALSEm biểu thức 2 trả về FALSE và biểu thức 3 trả về TRUE thì câu lệnh 3 được thực hiện. Nếu cả 3 biểu thức 1,2,3 đều trả về FALSE thì thực hiện câu lệnh 4.

Ngoài ra PHP còn cung cấp từ khoá elseif, chính là ghép giữa từ khoá else và if.

Câu lệnh while
Câu lệnh while dùng để tạo 1 vòng lặp, cú pháp của câu lệnh này như sau:

while ( biểu thức )
câu lệnh;
Được diễn giải như sau: trong khi biểu thức còn trả về giá trị TRUE thì tiếp tục thực hiện câu lệnh, sau khi thực hiện câu lệnh thì kiểm tra lại biểu thức, nếu vẫn còn trả về giá trị TRUE thì lại tiếp tục thực hiện câu lệnh...cứ tiếp tục như vậy cho tới khi nào biểu thức trả về giá trị FALSE thì ngưng.

Một ví dụ in ra các số từ 1 tới 10 với câu lệnh while:

<?php
$i = 1;
while ( $i <= 10 ) {
echo $i, "\n";
$i++;
} //end while
?>
Ghi chú: Câu lệnh $i++ tương đương với $i = $i+1;, câu lệnh này sẽ tăng giá trị của $i lên 1 qua mỗi lần lặp.

Câu lệnh do-while
Câu lệnh do-while cũng tương tự như câu lệnh white, chỉ khác một điểm là câu lệnh được thực hiện trước rồi biểu thức mới được kiểm tra sau, nếu biểu thức còn trả về giá trị TRUE thì tiếu tục thực hiện câu lệnh. Cú pháp của câu lệnh do-while như sau:

do {
câu lệnh;
} while ( biểu thức );

Một ví dụ in ra các số từ 1 tới 10 với câu lệnh do-while:

<?php
$i = 1;
do {
echo $i, "\n";
$i++;
} while ( $i < 10 );
?>

Câu lệnh for
Câu lệnh for cũng dùng để tạo vòng lặp. Đây là một trong những câu lệnh phức tạp nhất của PHP, cú pháp của nó như sau:

for ( biểu thức 1; biểu thức 2; biểu thức 3 )
câu lệnh;
Được diễn giải như sau:
  • Đầu tiên biểu thức 1 được thực hiện,
  • Tiếp theo biểu thức 2 được kiểm tra
    • Nếu trả về TRUE thì câu lệnh được thực hiện và sau đó thực hiện biểu thức 3.
    • Nếu trả về FALSE thì kết thúc câu lệnh for.
  • Kiểm tra lại biểu thức 2 và lặp lại quá trình như trên.

Một ví dụ in ra các số từ 1 tới 10 với câu lệnh for:

<?php
for ( $i = 0; $i < 10; $i++ ) {
echo $i, "\n";
} //end for
?>

Câu lệnh foreach
Câu lệnh foreach chỉ làm việc với array. Câu lệnh foreach có 2 dạng cú pháp như sau:

foreach ( $array as $value )
câu lệnh;
foreach ( $array as $key => $value )
câu lệnh;

Ta sẽ hiểu rõ hơn 2 dạng cú pháp này qua 2 ví dụ sau:

Ví dụ 1:

<?php
$a = array('a' => 1, 'b' => '2', 'c' => '3');

foreach ( $a as $value ) {
echo $value, "\n";
} //end foreach
?>
Chương trình trên sẽ in ra 3 số 1, 23.

Ví dụ 2:

<?php
$a = array('a' => 1, 'b' => '2', 'c' => '3');

foreach ( $a as $key => $value ) {
echo $key, "=", $value, "\n";
} //end foreach
?>
Chương trình trên sẽ in ra 3 chuỗi a=1, b=2c=3.

Câu lệnh switch
Câu lệnh switch hoạt động như là 1 loạt câu lệnh if ghép lại với nhau. Ta hãy xem câu lệnh if sau:

if ( $a == "abc" )
echo "Giá trị của a là abc";
} elseif ( $a == "def" )
echo "Giá trị của a là def";
} elseif ( $a == "123" ) {
echo "Giá trị của a là 123";
} else {
echo "Giá trị khác";
} //end if
3 câu lệnh if ở trên có thể được viết lại bằng câu lệnh switch như sau:
switch ( $a ) {
case "abc";
echo "Giá trị của a là abc";
break;
case "def";
echo "Giá trị của a là def";
break;
case "123";
echo "Giá trị của a là 123";
break;
default:
echo "Giá trị khác";
} //end switch

Câu lệnh break
Câu lệnh break sẽ dừng việc thực thi của các vòng lặp for, foreach, while, do-while và switch. Ở phần trước ta đã thấy câu lệnh break được sử dụng trong câu lệnh switch. Nếu không có break, câu lệnh switch ở phần trước sẽ thành:

switch ( $a ) {
case "abc";
echo "Giá trị của a là abc";
case "def";
echo "Giá trị của a là def";
case "123";
echo "Giá trị của a là 123";
default:
echo "Giá trị khác";
} //end switch
Nếu giá trị của $a là "abc" thì cả 4 chuỗi "Giá trị của a là abc", "Giá trị của a là def", "Giá trị của a là 123" và "Giá trị khác" sẽ được in ra.; nếu $a mang giá trị "def" thì 3 chuỗi "Giá trị của a là def", "Giá trị của a là 123" và "Giá trị khác" sẽ được in ra.
Ở đây ta muốn chỉ có 1 dòng duy nhất in ra tương ứng với giá trị của biến $a, nên ta thêm các câu lệnh break vào các phần case, để khi in ra chuỗi tương ứng với giá trị $a thì ta thoát ra khỏi câu lệnh switch.

Một ví dụ sử dụng câu lệnh break trong vòng lặp for:

for ( $i=1; $i<=10; $i++ ) {
echo $i;
if ( $i == 5 ) break;
}
Vòng lặp for ở trên thay vì in ra 10 số từ 1 đến 10, vòng lặp chỉ in ra 5 số từ 1 đến 5 mà thôi vì khi $i đạt giá trị 5, vòng lặp sẽ kết thúc do câu lệnh break.

Cách dùng câu lệnh break trong các vòng lặp foreach, while và do-while cũng tương tự.

Câu lệnh continue
Câu lệnh continue áp dụng lên các vòng lặp, lệnh continue sẽ bỏ qua lần lặp hiện thời và tiếp tục thực hiện các lần lặp tiếp theo. Để hiểu rõ hơn ta hãy xem ví dụ sau:

for ( $i=1; $i<=5; $i++ ) {
if ( $i == 2 ) continue;
echo $i;
}
Khi $i đạt giá trị 2, câu lệnh echo $i; sẽ được bỏ qua không thì hành nữa do câu lệnh continue. Và như vậy, đoạn lệnh trên khi chạy sẽ in ra các giá trị 1,3,4,5 (không có giá trị 2).

Cách dùng của câu lệnh continue trong các vòng lặp foreach, while, do-while cũng tương tự.



HÀM

Hàm do người dùng định nghĩa
Trong lập trình, có một số đoạn mã được dùng nhiều lần ở nhiều nơi khác nhau trong chương trình. Sẽ rất phiền và khó sửa lỗi nếu như ta phải viết lặp đi lặp lại 1 đoạn mã đó ở nhiều nơi. PHP cung cấp một giải pháp đó là hàm do người dùng định nghĩa. Ta có thể đưa đoạn mã đó vào trong 1 hàm, và ở chỗ nào cần dùng đoạn mã đó ta chỉ cần gọi hàm, khi cần sửa đổi, ta chỉ cần sửa đổi 1 chỗ duy nhất là nội dung của hàm chứ không cần phải sửa ở nhiều nơi trong chương trình.

Cú pháp để tạo 1 hàm do người dùng định nghĩa như sau:

function tênHàm($tham_số1, $tham_số2, ..., $tham _sốn) {
//thân hàm
echo "Testing";
return $kết_quả_trả_về;
} //end
Khi cần sử dụng hàm ở chỗ nào, ta chỉ cần dùng cú pháp tênHàm(các tham số cần thiết);

Ví dụ:

<?php
function testing() {
echo "Testing gunction";
echo 1;
echo 2;
echo 3;
} //end testing
testing();
testing();
testing();
?>

Lưu ý: Tên hàm cũng như tên biến chỉ bao gồm các ký tự chữ cái (a..z, A..Z), chữ số (0..9) và ký tự gạch dưới (_), ngoài ra tên hàm không được bắt đầu bằng chữ số, nhưng được phép bắt đầu bằng ký tự gạch dưới (tên hàm khác với tên biến chỗ này). Tên hàm trong PHP phân biệt chữ hoa và chữ thường, tức là testing và Testing là 2 tên hàm khác nhau.

Tham số của hàm
Hàm có thể nhận vào các tham số, ví dụ:

<?php
function testing($a) {
echo "Tham số là $a";
} //end testing
testing(123);
testing("abc");
?>
Ở ví dụ trên, lời gọi hàm testing(123); sẽ in ra dòng Tham số là 123 và lời gọi hàm testing("abc"); sẽ in ra dòng Tham số là abc.

Ta có thể gán giá trị mặc định cho tham số của hàm:

<?php
function testing($a="mặc định") {
echo "Tham số là $a";
} //end testing
testing();
?>
Khi tham số tương ứng của hàm không được truyền, tham số đó sẽ nhận giá trị mặc định. Đoạn chương trình ví dụ ở trên khi chạy sẽ in ra dòng Tham số là mặc định.

Giá trị trả về từ hàm
Hàm còn thể trả về 1 giá trị cho nơi gọi:

<?php
function binh_phuong($a) {
$ketqua = $a * $a;
return $ketqua;
} //end testing
echo binh_phuong(2);
?>
Đoạn chương trình trên khi chạy sẽ in ra số 4. Câu lệnh return biểu_thức; sẽ kết thúc hàm và trả về giá trị của biểu_thức cho nơi gọi.

PHP - Giới thiệu - Các bước chuẩn bị cần thiết!

CÀI ĐẶT PHP

Để thực hành các ví dụ trong loạt bài hướng dẫn bạn cần phải cài đặt sẵn PHP trong máy của bạn, hoặc bạn phải có 1 website/hosting hỗ trợ PHP. Bạn có thể tham khảo một số bài viết hướng dẫn cài đặt PHP tại các địa chỉ:
- http://www.diendantinhoc.net/?article=41bc312b49&cat=web_php
- http://www.diendantinhoc.net/tute/hethong/apache-gd-mysql-php-linux/
- http://www.diendantinhoc.net/tute/hethong/apache-mysql-php-perl/
- http://www.diendantinhoc.net/tute/hethong/IIS-Perl-PHP-MySQL-duyson/
Các ví dụ trong bài viết sẽ được viết và chạy test trên PHP version 4.3.x trên các hệ thống:
- Windows 2k Pro/Server, XP Pro, Webserver IIS.
- Linux Redhat 9, Webserver Apache 2.0.x


CHỌN 1 CHƯƠNG TRÌNH SOẠN THẢO PHP

Để soạn thảo các mã nguồn chương trình PHP, bạn cần có một chương trình soạn thảo văn bản.
Trên Linux bạn có thể dùng vi/vim, gvim, kwrite...
Trên Windows bạn có thể dùng GVim for Windows, EditPlus, EmEditor, Dreamweaver MX...

Nếu bí quá không có gì xài, bạn xài tạm Notepad của Windows cũng được luôn. Nhưng bạn đừng lo, ở đây có khá nhiều chương trình soạn thảo PHP miễn phí: http://www.freeprogrammingresources.com/phpide.html.

Các ví dụ trong bài viết sẽ được soạn thảo trên vi/vim, kwrite trên Linux hoặc EditPlusEmEditor trên Windows.
Theo kinh nghiệm cá nhân của tôi, nếu bạn soạn thảo mã nguồn PHP trên Windows thì EditPlusEmEditor là 2 ứng cử viên xuất sắc: nhỏ gọn, nhiều chức năng tiện lợi. EditPlus có trội hơn EmEditor một chút về mặt tiện ích, nhưng lại khá bất tiện nếu như bạn muốn gõ tiếng Việt Unicode trong mã nguồn PHP. EmEditor hỗ trợ tiếng Việt Unicode khá tốt, nhưng mỗi file lại được mở trong 1 cửa sổ riêng, hơi choáng chỗ nếu như bạn phải soạn thảo nhiều file cùng một lúc.


LƯU FILE VỚI TIẾNG VIỆT UNICODE

Nếu bạn sử dụng tiếng Việt Unicode trong chương trình, bạn nên lưu file với encoding UTF-8, và khi lưu nhớ bỏ tuỳ chọn Save BOM Signature. Nếu không, 3 ký tự đánh dấu sẽ được tự động chèn vào đầu file mã nguồn PHP. 3 ký tự này nhiều chương trình soạn thảo văn bản hỗ trợ Unicode sẽ không hiển thị ra màn hình khi bạn mở file, nên bạn sẽ không biết là có 3 ký tự này ở đầu file, do đó có thể xảy ra một số lỗi không lường được.

Nếu bạn dùng EmEditor, khi bạn lưu file lần đầu tiên, hoặc lúc bạn Save as, bạn chỉ cần chọn Code PageUTF-8 và bỏ chọn mục Add a Unicode Signature (BOM) đi là được. Từ lần save thứ 2 trở đi, hoặc khi bạn mở file đã được save rồi thì bạn không cần phải chọn lại nữa.
Saving File as UTF8 Encoding

Nếu bạn quên không bỏ mục chọn Add a Unicode Signature (BOM), 3 ký tự đánh dấu sẽ được tự động chèn vào đầu file, và hậu quả có thể là như thế này:
UTF8 - Error 1

Hoặc có thể còn tệ hại hơn thế:
UTF8 - Error 2

Nếu bạn mở file ra xem bằng một chương trình không hỗ trợ Unicode, bạn sẽ thấy có 3 ký tự ở ngay đầu file:
UTF8 - BOM

Cho nên bạn hãy nhớ bỏ 3 ký tự đánh dấu BOM ở đầu file khi lưu ở bảng mã Unicode.


CHỌN 1 VĂN PHONG MÃ NGUỒN

Chọn một văn phong nhất quán trong soạn thảo mã nguồn sẽ giúp code của bạn sáng sủa, dễ đọc trên nhiều môi trường khác nhau; và như vậy cũng phần nào giúp bạn tránh gặp lỗi và dễ sửa lỗi trong chương trình.

Bạn có thể áp dụng các qui tắc sau trong văn phong soạn thảo mã nguồn của bạn:
- Dùng ký tự tab khi cần thụt đầu dòng, đặt tab-stop bằng 4 space.
- Hàm/Thủ tục con:
/*
Chú thích về funcA, cách sử dụng, danh sách tham số, kết quả trả về...
*/
function funcA(tham số) {
...
} //end funcA

- Lệnh if...else:
if ( điều kiện ) {
...
} else {
...
} //end if

- Lệnh for, while:
for ( ... ) {
...
} //end for

while ( điều kiện ) {
...
} //end while

Ngoài ra có một số văn phong và qui tắc mà bạn nên áp dụng:

  • bắt đầu chương trình bằng , tuyệt đối tránh sử dụng vì nhiều server không hiểu/hỗ trợ nên rất có thể chương trình của bạn ở server này thì chạy, đem qua server khác thì "im re".
  • viết chương trình trong điều kiện môi trường safe_mode=On, register_globals=Off, display_errors=Off và trạng thái của magic_quotes_gpc là không xác định. Vì đây thường là các cài đặt mặc định của nhiều server, bạn nên tập viết chương trình trong điều kiện môi trường như vậy sẽ giúp cho chương trình của bạn tránh khỏi nhiều phiền hà khi chuyển từ server này sang server khác.
    Nếu bạn nằm quyền điều khiển server (VD bạn cài trên máy ở nhà để viết chương trình, bạn hãy nên chỉnh cấu hình file php.ini cho đồng bộ với đa số các server hosting khác:
    • safe_mode=On: bật chế độ safe_mode sẽ làm cho hệ thống an toàn hơn đôi chút.
    • register_globals=Off: tắt chế độ register_globals bạn sẽ không còn sử dụng trục tiếp được các biến được truyền thẳng cho chương trình. Ví dụ: script của bạn được truy cập qua địa chỉ http://domain/script.php?test=123. Với register_globals=Off, chương trình của bạn không thể trực tiếp truy cập biến $test để lấy giá trị 123 mà cần phải truy cập qua $_GET['test']. Bạn đừng lo, register_globals=Off sẽ làm chương trình được nạp nhanh hơn và an toàn hơn.
    • display_errors=Off: tắt chế độ hiển thị thông tin về lỗi ra trình duyệt. Như vậy mỗi khi có lỗi màn hình sẽ...trắng bóc. Tuy khó debug chương trình hơn 1 chút nhưng như vậy sẽ an toàn hơn vì khi có lỗi, các thông tin về server sẽ không bị lôi hết ra hiển thị trên trình duyệt.
    • log_errors=On: vì lỗi sẽ không được hiển thị ra màn hình nữa nên bạn cần phải log lại vào file để sau này còn biết đường mà debug.
    • magic_quotes_gpc=Off: tắt magic_quotes sẽ làm chương trình được nạp nhanh hơn.
    • error_log=C:\php\error_log: chỉ định tên file sẽ dùng để lưu trữ error log.
    Bạn có thể tham khảo file php.ini-recommended (nằm trong file Zip khi bạn download PHP) để xem cấu hình gợi ý do chính nhóm phát triển PHP đề xuất.