คำแนะนำเกี่ยวกับ PHP บน Windows

มิตรสหายหลายท่านเขียน PHP กันบน Windows ครับ ผมก็ไม่ได้ใช้นานแล้ว ตอนโน้นผมใช้ XAMPP มันก็ ok อยู่นะครับ แต่ถ้า project ที่คิดว่าจะใช้เร็ว ๆ นี้ก็อาจจะเลือกตัวเก่า ๆ หน่อยนะครับสัก PHP 5.3 เพราะว่า server หลายตัวยังใช้อยู่ อย่างเช่น Ubuntu 12.04 LTS ก็ยังใช้ PHP 5.3.10 อยู่ เป็นต้น ครับ

Kohana CLI (2)

หลังจาก เรียกใช้ Kohana จาก command line interface ได้แล้ว แต่ทีนี้อยากใส่ค่าตัวแปรอะไรเข้าไปด้วย ก็ทำง่ายๆ เลยมันมี option –get กับ –post อยู่

ยกตัวอย่างเช่น ผมมี controller ชื่อ home และ action คือ index และอยากส่งค่า x=10 และ y=abc เข้าไปทาง post method ก็ทำแบบนี้

php index.php –uri=”home/index” –post=”x=10&y=abc”

เสร็จละ

กรณีเจ๊งของ PHP และ regular expression เวลาเจอภาษไทย + UTF-8

ถ้ามี code แบบนี้ใช้ charset เป็น UTF-8

<?php
	print_r(preg_split("/\\s/", "ประเภท"));
?>

แบบนี้มันไม่น่าจะ split ได้เพราะว่า ไม่มี space ใน “ประเภท” เลยแต่มัน split ได้ซะงั้น

Array
(
    [0] => เธ›เธฃเธฐเน€เธ
    [1] => เธ—
)

แถวๆ “ภ” มันคงแปลงไปเป็นอะไรแล้ว code ไปเป็น space มั้ง

แต่ไม่ว่าจะเพราะว่าอะไร มีท่าแก้ง่ายๆ แบบนี้ใส่ u เข้าไป หายครับ

<?php
	print_r(preg_split("/\\s/u", "ประเภท"));
?>

ผมใช้ php 5.3.5 ที่มากับ xampp 1.7.4 และทดลองบน Windows 7 ครับ

Laemya – A lightweight web framework

ช่วงนี้ผมเขียน PHP ปกติใช้ CakePHP แต่คราวนี้อยากได้อะไรที่บางกว่า CakePHP สักหน่อย แต่ว่าก็ยังติดใช้ CakePHP อยู่ทำไปทำมาก็เลยก็โปรแกรมอะไรบางอย่างออกมา ไม่รู้ว่าเรียกว่า web framework ได้เปล่า แต่ก็แยกมันออกมาและตั้งชื่อว่า “แหลมหญ้า” (laemya) ตามเขาแหลมหญ้าอุทยานแห่งชาติที่ผมไปเที่ยวบ่อยที่สุด

พยายามจะเขียนเป็นแบบ MVC แต่ก็คงไม่ค่อยเหมือนเท่าไหร่ ไม่ได้อาศัพพวก mod_rewrite หลักๆ แล้วก็ยังใช้การไปเรียกไฟล์ตรงๆ เหมือนใช้ PHP ปกติ แต่ว่า มี code บนหัวไฟล์นิดหน่อยที่จะไปโหลดพวก controller และ model มาให้ แบบนี้ เช่นผมจะสร้างเว็บที่ http://localhost/user/laemya.php ผมก็ไปสร้างไฟล์ user/laemya.php ขึ้นมาแบบนี้

<?php
    require_once "../laemya.php";
    laemya_init(__FILE__);
?>
<?php function title() { return "Laemya test page"; } ?>
<?php laemya_header() ?>
<div>
<?php
    print_r($data);
?>
</div>
<?php laemya_footer() ?>

โปรแกรม 2 บรรทัดข้างบนจะไปสร้าง controller และสร้าง model ยัดใส่ controller ไว้ ส่วน $data ที่ไม่รู้มาจากไหนก็คือผลลัพธ์ที่คืนมาจาก controller

ก็เลยต้องไปสร้าง model รอไว้ก่อน ใน model/user.php

<?php
    class User extends AppModel {
        var $table = 'users';

        function __construct() {
            parent::__construct();
        }
}
?>

model นี้ก็ไม่ได้ถึงกับเป็น orm หรอก ก็แค่ไปเรียกใช้ mdb2 อีกที แต่ก็มีตัวช่วยบ้าง ตามที่ผมจะอยากใช้

ตาราง users หน้าตาประมาณนี้

mysql> desc users;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(11)      | NO   | PRI | NULL    | auto_increment | 
| username | varchar(255) | NO   | UNI | NULL    |                | 
| realname | text         | NO   |     | NULL    |                | 
| email    | varchar(255) | NO   | UNI | NULL    |                | 
| password | varchar(255) | NO   |     | NULL    |                | 
| group_id | int(11)      | NO   |     | NULL    |                | 
+----------+--------------+------+-----+---------+----------------+
6 rows in set (0.05 sec)

ทีนี้ก็ลองดู controller ชื่อ controller/user_controller.php

<?php
    class UserController extends Controller {
        function laemya() {
            return $this->User->findAll();          
        }
    }
?>

user/laemya.php มันก็จะมาเรียก method ชื่อ laemya ใน UserController เอง แล้ว UserController ก็ไป query database มาแบบง่ายๆ แล้วคืนผลไป

นอกจากข้างบนแล้ว laemya ก็ยังมี feature พวกนี้ (ที่ปกติ framework ก็มักจะมีกันหมด)

  • authentication – พอใส่ var $auth = true; ลงใน controller มันก็จะถูกเรียกใช้งาน ถ้าอยากให้ controller ถูก protect ก็สร้าง method ชื่อ before ใน controller แล้วเรียก $this->checkUser() ใน before
  • column แบบ json ใน model ใส่ var $jsonColumns = array(“ชื่อ column”) แล้ว model ก็จะแปลง json กับ php ให้เวลาสั่ง findAll กับ save
  • มี validator ด้วย โดยสร้าง method ชื่อ validate ใน model แล้ว return array ที่ประมาณ array(‘user’ => ‘is required’) ออกมา
  • กำหนดได้ว่าจะให้ใส่ model ไหนใน controller บ้างใช้ var $uses = array(‘ชื่อ model’, ‘ชื่อ model’ …);
  • พวก $this->redirect และ $this->flash อะไรแบบนี้ก็ใช้ได้ด้วย

อีกนิดหนึ่งคือ laemya ไม่ได้อ่าน scheme ของ database เวลาจะใช้ save ใน model ต้องบอกมันด้วยว่ามี column อะไร type อะไร แบบนี้

<?php
    class MyModel extends AppModel {
        var $table = 'mytable';
        var $jsonColumns = array('tree');
        var $columns = array('owner_id', 'tree');
        var $types = array('integer', 'text');

        function __construct() {
            parent::__construct();
        }
    }
?>

ถ้าอยาก query ซับซ้อนขึ้นหน่อยก็ต้องเขียน SQL

<?php
    class User extends AppModel {
        var $table = 'users';

        function __construct() {
            parent::__construct();
        }
        
        function auth($email, $password) {
            $types = array('text', 'text');
            $password = md5($password);
            $sth = $this->db->prepare("select id from " . 
                $this->table . 
                " where email=? and password=?", $types);
            $data = array($email, $password);
            $result = $sth->execute($data);
            if (PEAR::isError($result)) 
                die($result->getMessage());
            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
            return $row;
        }
    }
?>

หลักแล้วก็ใช้ mdb2 แต่ว่าต่อไปก็อาจจะมีตัวช่วยเพิ่มขึ้น database ต่อที่ไหน ต้องไปแก้ใน cfg/config.php และพร้อม base url …

ถ้าทราบว่ามีโครงการไหนทำแนวๆ นี้อยู่แล้วช่วยบอกผมด้วยนะครับ เผื่อจะเลิกทำเอง

ลืมบอกว่า project อยู่ที่ http://laemya.sourceforge.net/ ตอนนี้ยังไม่มี package ครับ แต่ว่าสามารถโหลดได้โดย

hg clone http://laemya.hg.sourceforge.net:8000/hgroot/laemya/laemya 

Dynamic class instantiation ใน PHP

ไม่ทราบว่าใช้คำถูกต้องหรือเปล่านะครับ ประมาณว่าถ้าผมครับ คืออยากจะสร้าง class ตาม string ที่ให้มาเวลารัน แทนที่จะต้องบอกว่า class ชื่ออะไร วิธีก็คือใช้ reflection class อ่านมาจาก stackoverflow

<?php
    class Toto {
        function printToto() {
            print "This is Toto.\n";
        }
    }
    $className = "Toto";
    $reflectionClass = new ReflectionClass($className);
    $toto = $reflectionClass->newInstance();
    $toto->printToto();
?>

เวลาจะเปลี่ยนชื่อ class ที่จะเอามาสร้าง object ก็เปลี่ยนที่ $className ได้เลย กะว่าจะเอามาใช้กับ controller และ model