레이블이 PHP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 PHP인 게시물을 표시합니다. 모든 게시물 표시

Memcached 설치 및 설정하고 테스트 하기 by Vins

우선 작업하기 전에
memcached (서버 데몬)
memcache (php-memcache 클라이언트) 이 두개의 버젼을 일치해야 한다
설치 진행은
먼저 서버 memcached 1.4.5
클라이언트 memcache 2.2.5를 사용하였다
버젼이 안 맞으면 테스트가 되지 않는다

memcached
•memcached: 基本情報
•memcacheセットアップ
◦memcacheセットアップ[peclパッケージ編]
■memcacheインストール
■PECL::memcacheパッケージコンパイル
■PHP設定
•memcachedセットアップ
◦memcachedセットアップ[peclパッケージ編]
■memcached実行ユーザー作成
■memcachedインストール
■memcachedコンパイル
■memcached動作確認
■memcachedの設定確認
■自動起動設定
■サービスの起動
◦memcachedインストール[yum編]
■yumのリポジトリ更新
■memcachedのインストール
■memcachedの起動
•[資料]セッションセーブハンドラに登録
◦php.iniの場合
◦.htaccessの場合
◦プログラムの場合

memcached: 基本情報 †
http://memcached.org/

特集:memcachedを知り尽くす
http://gihyo.jp/dev/feature/01/memcached

memcacheはデーモン(deamon):memcached
クライアント(client):memcache
で構成されています。


↑
memcacheセットアップ †
↑
memcacheセットアップ[peclパッケージ編] †
↑
memcacheインストール †
参照PHP インストール手順
memcacheのパッケージをダウンロードする


# echo "http_proxy=http://192.168.34.2:8080/" >> /etc/wgetrc
# #IDC以外の時は必要ない
# #間違えて作ってしまった場合は
# #rm /etc/wgetrc で消しておく
# cd /usr/local/src
# wget http://pecl.php.net/get/memcache-2.2.5.tgzダウンロードしたパッケージを解凍する

# tar -zxvf memcache-2.2.5.tgz
# cd memcache-2.2.5↑
PECL::memcacheパッケージコンパイル †
phpizeを使ってPECL::memcacheのパッケージをコンパイル


# /usr/local/php/bin/phpize && ./configure --enable-memcache --with-php-config=/usr/local/php/bin/php-config && makememcacheのモジュールをphpのモジュールにコピーします。


# cp modules/memcache.so /usr/lib/php/modules/↑
PHP設定 †
php.iniに次の設定を行う。
※phpがrpmもしくyumインストールの場合は
 memcached.iniを追加して設定を書きこみます。


# vi /etc/php.d/memcached.ini■設定内容


[memcache]
extension=memcache.so
memcache.allow_failover = 1
memcache.max_failover_attempts=20
memcache.chunk_size =8192
memcache.default_port = 11211
session.save_handler = memcache
session.save_path = tcp://127.0.0.1:11211


↑
memcachedセットアップ †
↑
memcachedセットアップ[peclパッケージ編] †
↑
memcached実行ユーザー作成 †
memcached用のアカウント「memcached」を作成する
# sudo groupadd memcached
# sudo useradd -g memcached -s /sbin/nologin -d /nonexistent memcached↑
memcachedインストール †
memcachedのパッケージをダウンロードする


# cd /usr/local/src
# wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz
# tar zxvf memcached-1.4.5.tar.gz
# cd memcached-1.4.5↑
memcachedコンパイル †
コンパイルします。

# ./configure
# make
# make install※パッケージがない場合はyumでインストール


# yum install -y libevent-devel.i386↑
memcached動作確認 †
# memcached -d -m 64 -p 11211 -l 127.0.0.1 -u memcached↑
memcachedの設定確認 †
/etc/init.dにスクリプトを書く

# vi /etc/init.d/memcached#!/bin/bash
#
# memcached
#
# chkconfig: - 55 45
# description: The memcached daemon is a network memory cache service.
# processname: memcached
# config: /etc/sysconfig/memcached

# Source function library.
. /etc/rc.d/init.d/functions

#Config
TARGET=memcached
DSN_BIN=/usr/local/bin/${TARGET}

PORT=11211
USER=memcached
MAXCONN=1024
CACHESIZE=768
OPTIONS="-l 127.0.0.1"

if [ -f /etc/sysconfig/memcached ]; then
. /etc/sysconfig/memcached
fi

start()
{
echo -n "Starting ${TARGET}: "
daemon ${DSN_BIN} -d -p ${PORT} -u ${USER} -m ${CACHESIZE} ${OPTIONS}
echo
touch /var/lock/subsys/memcached
}

stop()
{
echo -n "Shutting down ${TARGET}: "
killproc ${DSN_BIN}
echo
rm -f /var/lock/subsys/memcached
}

case "$1" in
start)
start
;;
stop)
stop
;;
status)
status ${TARGET}
;;
restart|reload)
stop
start
;;
*)
echo "Usage: `basename $0` {start|stop|status|reload|restart}" >&2
exit 1
esac
exit 0
権限を変更する

# chmod 777 /etc/init.d/memcached↑
自動起動設定 †
# chkconfig --add memcached
# chkconfig memcached on
# chkconfig --list memcached↑
サービスの起動 †
/etc/init.d/memcached restart↑
memcachedインストール[yum編] †
↑
yumのリポジトリ更新 †
標準ではmemcachedが追加されていないのでのリポジトリを更新する。

# cd /usr/local/src
# wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
# rpm -Uhv rpmforge-release-0.3.6-1.el5.rf.i386.rpmこれでリポジトリにmemcachedが追加される

↑
memcachedのインストール †
yumで必要なパッケージをインストール

# yum -y install libevent memcached php-pecl-memcache zlib-devel re2cmemcachedの設定は/etc/sysconfig/memcachedを編集する。動かすだけならデフォルトのままでOK。

↑
memcachedの起動 †
/etc/init.d/memcached startサービスを自動起動にしておく。

chkconfig memcached on↑
[資料]セッションセーブハンドラに登録 †
↑
php.iniの場合 †
session.save_handler = memcache
session.save_path = tcp://127.0.0.1:11211↑
.htaccessの場合 †
php_value session.save_handler "memcache"
php_value session.save_path "tcp://127.0.0.1:11211"↑
プログラムの場合 †
ini_set("session.save_handler", "memcache");
ini_set("session.save_path", "tcp://127.0.0.1:11211");

다 설정 하였다면 ..

telnet 127.0.0.1 11211 접속하여
stats <-- 입력해 보라
응답이 있다면 아래 목록이 출력 될 것이다 .

이하는 ssh의 까만 화면이라고 생각해자

# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
stats
STAT pid 22991
STAT uptime 1612
STAT time 1271830666
STAT version 1.4.5
STAT pointer_size 32
STAT rusage_user 0.000999
STAT rusage_system 0.008998
STAT curr_connections 11
STAT total_connections 16
STAT connection_structures 13
STAT cmd_get 4
STAT cmd_set 4
STAT cmd_flush 0
STAT get_hits 3
STAT get_misses 1
STAT delete_misses 0
STAT delete_hits 0
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 3080
STAT bytes_written 2975
STAT limit_maxbytes 67108864
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT bytes 744
STAT curr_items 1
STAT total_items 4
STAT evictions 0
STAT reclaimed 0


봤으면 quit !!

Memcached 설치 및 설정하기 그리고 주의 사항

Memcached 는 데이터를 메모리에 저장하며 분산처리가 가능하고 매우 빠른 성능을 지닌 캐시 입니다.

- libevent 설치
Memcached 는 libevent 를 필요로 하므로 먼저 설치를 진행하겠습니다.

http://monkey.org/~provos/libevent/

[root@yongobk ~]# cd /usr/local/src
[root@yongobk ~]# wget http://monkey.org/~provos/libevent-1.4.13-stable.tar.gz
[root@yongobk ~]# tar xzvf libevent-1.4.13-stable.tar.gz
[root@yongobk ~]# cd libevent-1.4.13-stable
[root@yongobk ~]# ./configure
[root@yongobk ~]# make ; make install


- Memcached 설치
아래 주소에서 최신버전을 다운로드 하고 설치를 진행합니다.

http://code.google.com/p/memcached/downloads/list

[root@yongobk ~]# cd /usr/local/src
[root@yongbok ~]# wget http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz
[root@yongbok ~]# tar xzvf memcached-1.4.4.tar.gz
[root@yongbok ~]# cd memcached-1.4.4
[root@yongbok ~]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local
[root@yongbok ~]# make ; make install


- Memcached 실행

[root@yongbok ~]# /usr/local/memcached/bin/memcached -u nobody &


- Memcached PHP Extension 설치

http://pecl.php.net/package/memcache

[root@yongobk ~]# cd /usr/local/src
[root@yongbok ~]# wget http://pecl.php.net/get/memcache-2.2.5.tgz
[root@yongbok ~]# tar xzvf memcache-2.2.5.tgz
[root@yongbok ~]# cd memcache-2.2.5
[root@yongbok ~]# /usr/local/php5/bin/phpize
[root@yongbok ~]# ./configure --with-php-config=/etc/php/bin/php-config
[root@yongbok ~]# make ; make install

Installing shared extensions: /usr/local/php5/lib/php/extensions/no-debug-non-zts-20060613/


php.ini 파일에 아래 내용 추가 합니다.

[root@yongbok ~]# vi /usr/local/apache2/conf/php.ini

[memcache]
extension_dir=/usr/local/php5/lib/php/extensions/no-debug-non-zts-20060613/
extension=memcache.so
memcache.allow_failover=1
memcache.max_failover_attempts=100
memcache.chunk_size=32768
memcache.default_port=11211


- Apache 재시작

[root@yongbok ~]# /usr/local/apache2/bin/apachectl restart


- PHP 에 Memcached 가 적용 되어 있는지 확인

[root@yongbok ~]# echo '' > /var/www/phpinfo.php





참고
http://www.ibm.com/developerworks/kr/library/os-php-fastapps3/

[세션을 메모리캐싱을 사용할 경우 주의 사항 ]
memcache를 사용하는 중 세션 정보가 유지되지 않아 그것을 해결하는데
많은 시간을 소비하였습니다. 저의 경우 모델자체를 세션에 저장하였었는데 그것의 데이터가 많아지면 저절로 기존 데이터가 사라지는 것이었습니다. 그래서 필요한 데이터만 저장하니까 그러한 문제는 발생되지 않았습니다

memcached + Session Database
- memcached의 원래 목적이 데이터베이스나 파일 데이터를 캐시하는 것임

- 세션 데이터를 데이터베이스로 만들어 넣고, session handler 부분에서 memcached를 호출하게 만들면 될 듯.

- 데이터베이스를 사용하는 안정성 + 세션 공유 문제 해결 + memcached에 의한 성능 향상까지 기대할 수 있지 않을까?

- 이 부분은, 좀더 생각해보면서, 방법을 찾아봐야 할 듯...
<- 곰곰히 생각해보니, 약간 부정적. 세션 데이터는 read보다는 update가 압도적으로 많음. 따라서, 캐시 효과는 작음.



Memcache & MySQL PHP Session Handler PHP code for session db + memcached
http://www.softwareprojects.com/resources/programming/t-php-sessionsave_handler-and-database-sessions-debu-1797.html
http://www.softwareprojects.com/resources/programming/t-memcached-for-php-sessions-1654.html

apache2.2 + php 5.2 설치 및 설정 방법




1. Apache 받기

    http://httpd.apache.org/download.cgi 에서 아파치를 구할 수 있다.

    여기에 설치 한 것은 2.2.11을 (no ssl) MSI Installer로 버전으로 설치 했다.

    바로 받을 수 있는 주소

    http://apache.mirror.cdnetworks.com/httpd/binaries/win32/apache_2.2.11-win32-x86-no_ssl.msi







2. Apache 설치

   다운 받은 apache_2.2.11-win32-x86-no_ssl.msi 을 실행 한다.



2. A. 설치 초기 메시지



설치 한다고 말해 준다... 다음



2. B. 라이센스 동의

라이센스에 동의 할 것인지 물어본다.

설치하려면 I accept the terms in the license agreement 선택 후, 다음







2. C. 아파치 서버 내용

아파치 서버에 대한 내용들... 읽어 보고 다음.







2. D. 서버 정보 입력

서버의 정보를 입력하는 부분이다. 아래 항목들을 자신의 환경에 맞게 넣어준다. 다음~







2. E. 설치 타입

설치 타입을 정한다. Typical 하면 된다. 다음~







2. F. 설치 폴더

아파치가 설치될 폴더를 물어본다. 기본으로는 Program Files 밑에 Apache Software Foundation 에 설치가 되게 된다.  자신이 원하는 위치로 설정을 바꾼다.

여기서는 C:\Apache에 설치 했다







2. G. 인스톨

인스톨을 눌러 설치한다.







2. H. 설치 중

설치 중~~~







2. I. 설치 완료

설치 완료 되었다~!











3. PHP 받기

http://www.php.net/downloads.php 에서 php를 받을 수 있다.  여기서는 PHP 5.2.8 zip package를 받았다.

바로 받기 : http://kr2.php.net/get/php-5.2.8-Win32.zip/from/a/mirror











4. PHP 설치



  4. A. 해당 파일을 압축을 풀고 C:\php 에 옮겼다. 어디에 설치하든 그건 자기마음이다.



  4. B. php 파일안에 있는 php.ini-recommended를 php.ini로 바꾼다.



  4. C. 해당 파일을 열어서 아래 부분을 수정한다

---------------------------------

 

;;;;;;;;;;;;;;;;;;;;;;;;;

; Paths and Directories ;

;;;;;;;;;;;;;;;;;;;;;;;;;



; UNIX: "/path1:/path2"

;include_path = ".:/php/includes"

;

; Windows: "\path1;\path2"

include_path = ".;c:\php\includes"          // 자신의 php 설치 폴더 밑으 includes 폴더를 지정한다.

---------------------------------







 

5. Apache 설치 하기



   5. A. 아파치가 설치된 폴더아래의 conf/extra에 httpd-php.conf 이름의 빈 파일을 만든다.

           여기서는 C:\Apache에 아파치를 설치 했으므로 C:\Apache\conf\extra에 httpd-php.conf를 만든다.



   5. B.  만든 파일을 텍스트 편집기에서 열어서 아래와 같이 적고 저장한다.

--------------------------------------

 

# PHP configuration

 

# PHP 5 module setup

 

LoadModule php6_module "C:/php/php5apache2_2.dll"

 

PHPIniDir "C:/php"

 



AddType application/x-httpd-php .php

 

AddHandler application/x-httpd-php .php

 

AddType application/x-httpd-php-source .phps

--------------------------------------



 

   5. C. 아파치가 설치된 폴더아래의 conf에 있는 httpd.conf 파일을 열어서 맽끝에 아래의 내용을 추가한다

--------------------------------------

# PHP 5 settings

Include conf/extra/httpd-php.conf

 

--------------------------------------









 

6. 설치확인



    6. A. 아파치가 설치된 폴더의 htdocs 폴더에 phpinfo.php 파일을 만들어서 제대로 설치 되었는지 확인한다.


--------------------------------------

<?php

    phpinfo();

?>

--------------------------------------

 

  

   6. B.  브라우저를 열고  http://localhost/phpinfo.php 를 열어서 아래 처럼 서버 정보가 나오면 정상적인 설치가 된것이다.







 







 

PHP+LOB 두개 이상의 CLOB 이용하기

PHP와 Oracle을 연동할 때는 다음과 같은 두가지의 문제가 가장 크게 대두됩니다.

* 페이징 처리
* LOB 타입의 처리

페 이징 처리야 사실 쿼리문을 개발하는 문제이니 Oracle SQL문만 익숙해지면 처리하는데 크게 어렵지 않습니다. 그런데 LOB타입은 쿼리문말고도 별도의 추가작업을 해줘야 하므로 아주 골치를 겪게 됩니다. 그래서 PHP와 Oracle 연동할 때 컬럼 타입을 되도록 LOB 타입으로 안잡으려 노력합니다만... 그게 그렇게 잘 되지 않죠... -_-ㅋ

요즘 그누보드 4를 Oracle 버전으로 포팅하는 작업을 하고 있습니다. 오랜만에 PHP와 Oracle을 연동하다보니 MYSQL의 text 타입을 전부 CLOB으로 처리해줘야 되더군요. 물론 그 중 상당수는 varchar2(4000)로 충분히 커버되는 것이지만, 최대한 그누보드 4의 골격을 해치지 않기 위해서 모두 CLOB으로 변환했습니다. 그러다 보니 한번에 두개 이상의 CLOB을 insert/update하는 일이 발생하게 되었습니다.

이전에도 PHP상에서 CLOB 타입을 핸들링한 적이 많았지만, 보통 한 테이블에 하나정도의 LOB타입이 있는 경우가 많았습니다. 그래서 두개 이상 해본적이 거의 없었던 것 같아서 이리저리 테스트해봤습니다. 되도록 한방에 처리할 수 있는 방안쪽으로 방향을 잡았습니다.

결국 한방에는 되지 않는다로 결론이 나버렸지만, 이 기회에 두개 이상의 CLOB을 핸들링하는 방법을 정리하게 되어 그리 헛된 고생을 한 것은 아닌 것 같습니다. 아 참! Oracle 10g 기반 최신 OCI를 받으면 MYSQL의 text 필드에 내용을 넣듯이 바로 한번에 된다는 글을 검색하는 도중 찾게 되었습니다. 다음에 한번 테스트 해봐야 겠네요.

각설하고... Oracle에서 LOB 처리를 하기 위해서는 다음과 같은 함수들이 추가적으로 필요합니다.

string OCINewDescriptor ( int connection [, int type])
int OCIBindByName ( int stmt, string ph_name, mixed & variable, int length [, int type])

그리고 두개 이상의 CLOB을 insert할 경우의 처리 순서는 다음으로 요약할 수 있습니다.

1. ROWID에 대한 Descriptor를 생성한다.
2. clob 칼럼을 제외한 나머지 칼럼이 포함된 insert 구문을 실행한다. 이 때 insert된 행의 ROWID를 Descriptor와 연결해 놓는다.
3. ROWID를 이용해 clob 칼럼을 하나씩 update를 한다.
4. 3의 과정을 CLOB 칼럼수만큼 반복한다.
5. 작업이 끝났으면 불필요한 리소스를 반환한다.

update의 경우는 위의 3~5과정과 동일하므로 생략하겠습니다. 그럼 위의 과정을 직접 코딩해보겠습니다. 먼저 테스트 테이블을 만듭니다.

create table aaa ( rnum number(7), clob1 clob, clob2 clob);

그리고 위의 테이블에 데이터를 넣어보겠습니다.

$dbconn = @OCILogon('test', 'test123', 'ora10g');

$sql = "insert into aaa (rnum) values (1) returning ROWID into :rid"; --- [1]

$stmt1 = OCIParse($dbconn, $sql); --- [2]
$rowid = OCINewDescriptor($dbconn, OCI_D_ROWID); --- [3]
OCIBindByName($stmt1, ":rid", &$rowid, -1, OCI_B_ROWID); --- [4]
OCIExecute($stmt1, OCI_DEFAULT); --- [5]
OCIFreeStatement($stmt1); --- [6]

$clob = OCINewDescriptor($dbconn, OCI_D_LOB); --- [7]

$content = array(); --- [8]
$content[0] = "CLOB 첫번째 내용입니다..";
$content[1] = "CLOB 두번째 내용입니다.";

$result = true;
for($i=0; $i<2; $i++) { --- [9]
$update = "update aaa set clob".($i+1)." = empty_clob() where ROWID = :rid returning clob".($i+1)." into :clob"; --- [10]
$stmt2 = OCIParse($dbconn, $update);
echo $update."
";
OCIBindByName($stmt2, ":rid", &$rowid, -1, OCI_B_ROWID);
OCIBindByName($stmt2, ":clob", &$clob, -1, OCI_B_CLOB); --- [11]
OCIExecute($stmt2, OCI_DEFAULT);

if($clob->save($content[$i])) { --- [12]
echo "

CLOB".($i+1)." 입력 성공

";
$result &= true; --- [13]
} else {
echo "

CLOB".($i+1)." 입력 실패

";
$result &= false;
}
OCIFreeStatement($stmt2);
}

echo "최종결과: ".(($result)? "true": "false")."
";
if($result) OCICommit($dbconn); --- [14]
else OCIRollback($dbconn);

OCIFreeDesc($rowid); --- [15]
OCIFreeDesc($clob); --- [16]
OCILogoff($dbconn);
?>

[1]: clob 칼럼은 나중에 update를 이용해서 집어넣을 것이므로, clob이 아닌 칼럼만 일단 insert를 합니다. 만일 clob 형 타입을 NOT NULL로 잡았다면 empty_clob() 함수를 이용해서 일단 빈공간을 만들어야 겠죠.
[2]: 일단 쿼리를 파싱합니다.
[3]: ROWID를 받아오기 위해 Descriptor를 생성합니다. 나중에 해당행에 CLOB을 집어넣기위한 식별자로 사용할 것입니다.
[4]: 파싱된 쿼리와 Descriptor를 바인딩시킵니다.
[5]: 쿼리 실행! 오라클은 기본으로 트랜잭션을 이용합니다. 이런 장점을 그대로 가지고 가려면, 두번째 인자에 OCI_DEFAULT를 지정하는 것을 잊지 말아야겠죠?
[6]: Statement를 해제합니다.
[7]: 이제 본격적으로 CLOB을 처리하기 위해 우선 CLOB Descriptor를 생성합니다.
[8],[9]: 이부분은 반복적인 업데이트 구문처리를 편하게 하기 위해 그냥 만든겁니다. 꼭 이렇게 해야한다는 법은 없습니다.
[10]: 실제로 CLOB 데이터를 넣기 위한 SQL입니다. 엄밀히 말하면 데이터가 들어갈테니 공간을 마련해 놓으라는 지시를 하는 것이죠. 실제 데이터 저장은 [12]에서 하게 됩니다.
[11]: 파싱된 쿼리에 CLOB Descriptor를 연결시킵니다.
[12]: 쿼리가 성공적으로 실행되면 실제로 데이터를 저장해야 합니다. LOB 객체의 save() 함수를 사용합니다.
[13]: 이건 나중에 트랜잭션의 Commit/Rollback을 정하기 위한 장치입니다. 비트연산을 이용해서 처리했습니다.
[14]: Commit 혹은 Rollback 합니다.
[15],[16]: 이제 모든 작업이 완료되었으므로 필요없는 Descriptor를 해제하는 작업을 합니다.

-------------------------------------------------------

이 것은 두개의 이상의 CLOB 데이터를 처리하기 위한 것입니다. 만약 한개의 CLOB 데이터를 처리한다면 insert 구문에서 모두 처리가 가능합니다.

php로 xss막는 함수 RemoveXSS()

function RemoveXSS($val) {
// remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
// this prevents some character re-spacing such as <java\0script>
// note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
$val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val);

// straight replacements, the user should never need these since they're normal characters
// this prevents like <IMG SRC=@avascript:alert('XSS')>
$search = 'abcdefghijklmnopqrstuvwxyz';
$search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$search .= '1234567890!@#$%^&*()';
$search .= '~`";:?+/={}[]-_|\'\\';
for ($i = 0; $i < strlen($search); $i++) {
// ;? matches the ;, which is optional
// 0{0,7} matches any padded zeros, which are optional and go up to 8 chars

// @ @ search for the hex values
$val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
// @ @ 0{0,7} matches '0' zero to seven times
$val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
}

// now the only remaining whitespace attacks are \t, \n, and \r
$ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
$ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
$ra = array_merge($ra1, $ra2);

$found = true; // keep replacing as long as the previous round replaced something
while ($found == true) {
$val_before = $val;
for ($i = 0; $i < sizeof($ra); $i++) {
$pattern = '/';
for ($j = 0; $j < strlen($ra[$i]); $j++) {
if ($j > 0) {
$pattern .= '(';
$pattern .= '(&#[x|X]0{0,8}([9][a][b]);?)?';
$pattern .= '|(�{0,8}([9][10][13]);?)?';
$pattern .= ')?';
}
$pattern .= $ra[$i][$j];
}
$pattern .= '/i';
$replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
$val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
if ($val_before == $val) {
// no replacements were made, so exit the loop
$found = false;
}
}
}
return $val;
}

PHP성능향상 42가지 TIP

1. If a method can be static, declare it static. Speed improvement is by a factor of 4.
메쏘드가 static이 될 수 있다면 static으로 선언하라. 4배 빨라진다.

2. echo is faster than print.
echo가 print보다 빠르다.

3. Use echo’s multiple parameters instead of string concatenation.
문자열을 이어붙이지 말고, echo를 이용하여 여러 개의 파라미터를 적어라.

4. Set the maxvalue for your for-loops before and not in the loop.
for 루프을 위핸 최대값(탈출조건)을 루프 안에서가 아니고 루프 시작 이전에 지정하라.

5. Unset your variables to free memory, especially large arrays.
메모리를 해제하기 위해 변수를 unset하라. 특히 커다란 배열은 그래야 된다.

6. Avoid magic like __get, __set, __autoload
__get, __set, __autoload와 같은 마법을 피해라.

7. require_once() is expensive
require_once()는 비싸다.

8. Use full paths in includes and requires, less time spent on resolving the OS paths.
include와 require를 사용할 때, 경로를 찾는데 시간이 적게 걸리는 full path를 사용하라.

9. If you need to find out the time when the script started executing, $_SERVER[’REQUEST_TIME’] is preferred to time()
스크립트가 언제 실행했는지 알고 싶으면 time()보다 $_SERVER[’REQUEST_TIME’]이 좋다.

10. See if you can use strncasecmp, strpbrk and stripos instead of regex
정규표현식보다는 가능하면 strncasecmp나 strpbrk, stripos를 사용하라.
* 역주
strncasecmp: 두 문자열의 앞쪽 일부가 대소문자 구분없이 일치하는지 확인할 때 사용
strpbrk: 문자 집합에 속한 특정 문자가 문자열에 나타나는지 확인할 때 사용
stripos: 대소문자 구분없이 특정 문자열이 다른 문자열에 포함되는지 확인할 때 사용

11. str_replace is faster than preg_replace, but strtr is faster than str_replace by a factor of 4
str_replace가 preg_replace보다 빠르지만, strtr은 str_replace보다 4배 빠르다.

12. If the function, such as string replacement function, accepts both arrays and single characters as arguments, and if your argument list is not too long, consider writing a few redundant replacement statements, passing one character at a time, instead of one line of code that accepts arrays as search and replace arguments.
만약 문자열 교체 같은 함수가 배열과 문자열을 인자로 받아들이면, 그리고 그 인자 리스트가 길지 않다면, 배열을 한 번에 받아들여서 처리하는 것 대신에 한 번에 문자열을 하나씩 넘겨서 처리하는 것을 고려해봐라.

13. It’s better to use select statements than multi if, else if, statements.
여러 개의 if/else if 문장 대신에 select 문장을 사용하는 게 더 좋다.

14. Error suppression with @ is very slow.
@를 이용한 에러 출력 방지는 매우 느리다.

15. Turn on apache’s mod_deflate
Apache의 mod_deflate를 켜라.
*역주
mod_deflate는 서버의 출력을 클라이언트에게 보내기 전에 압축하는 모듈임

16. Close your database connections when you’re done with them
DB를 다 사용했으면 연결을 닫아라.

17. $row[’id’] is 7 times faster than $row[id]
$row[’id’]가 $row[id]보다 7배 빠르다.

18. Error messages are expensive
에러 메시지는 비싸다.

19. Do not use functions inside of for loop, such as for ($x=0; $x < count($array); $x) The count() function gets called each time.
for 루프의 표현식 안에서 함수를 사용하지 마라.
for ($x = 0; $x < count($array); $x)에서 count() 함수가 매번 호출된다.

20. Incrementing a local variable in a method is the fastest. Nearly the same as calling a local variable in a function.
메쏘드 안에서 지역 변수를 증가시키는 것이 거의 함수 안에서 지역 변수를 호출(증가?)하는 것만큼 빠르다.

21. Incrementing a global variable is 2 times slow than a local var.
전역 변수를 증가시키는 것이 지역 변수를 증가시키는 것보다 2배 느리다.

22. Incrementing an object property (eg. $this->prop++) is 3 times slower than a local variable.
객체의 멤버변수를 증가시키는 것이 지역 변수를 증가시키는 것보다 3배 느리다.

23. Incrementing an undefined local variable is 9-10 times slower than a pre-initialized one.
값이 지정되지 않은 지역 변수를 증가시키는 것이 미리 초기화된 변수를 증가시키는 것보다 9~10배 느리다.

24. Just declaring a global variable without using it in a function also slows things down (by about the same amount as incrementing a local var). PHP probably does a check to see if the global exists.
전역 변수를 함수 안에서 사용하지 않으면서 그저 선언하기만 해도 (지역 변수를 증가시키는 것만큼) 느려진다. PHP는 아마 전역 변수가 존재하는지 알기 위해 검사를 하는 것 같다.

25. Method invocation appears to be independent of the number of methods defined in the class because I added 10 more methods to the test class (before and after the test method) with no change in performance.
메쏘드 호출은 클래스 안에서 정의된 메쏘드의 갯수에 독립적인 듯 하다. 왜냐하면 10개의 메쏘드를 테스트 클래스에 추가해봤으나 성능에 변화가 없었기 때문이다.

26. Methods in derived classes run faster than ones defined in the base class.
파생된 클래스의 메쏘드가 베이스 클래스에서 정의된 것보다 더 빠르게 동작한다.

27. A function call with one parameter and an empty function body takes about the same time as doing 7-8 $localvar++ operations. A similar method call is of course about 15 $localvar++ operations.
한 개의 매개변수를 가지고 함수를 호출하고 함수 바디가 비어있다면(함수 내부에서 아무것도 실행하지 않는다면) 그것은 7~8개의 지역변수를 증가시키는 것과 똑같은 시간을 차지한다. 비슷한 메쏘드 호출은 마찬가지로 15개의 지역변수를 증가시키는 연산쯤 된다.

28. Surrounding your string by ‘ instead of ” will make things interpret a little faster since php looks for variables inside “…” but not inside ‘…’. Of course you can only do this when you don’t need to have variables in the string.
문자열을 이중 따옴표 대신에 단일 따옴표로 둘러싸는 것은 좀 더 빠르게 해석되도록 한다. 왜냐하면 PHP가 이중 따옴표 안의 변수를 찾아보지만 단일 따옴표 안에서는 변수를 찾지 않기 때문이다. 물론 문자열 안에서 변수를 가질 필요가 없을 때만 이렇게 사용할 수 있다.

29. When echoing strings it’s faster to separate them by comma instead of dot. Note: This only works with echo, which is a function that can take several strings as arguments.
문자열을 echo할 때 마침표 대신에 쉼표로 분리하는 것이 더 빠르다.
주의: 이것은 여러 문자열을 인자로 받아들이는 함수인 echo로만 작동한다.

30. A PHP script will be served at least 2-10 times slower than a static HTML page by Apache. Try to use more static HTML pages and fewer scripts.
Apache에 의해 PHP 스크립트는 정적 HTML 페이지보다 최소 2에서 10배 느리게 서비스된다. 더 많은 정적 HTML 페이지와 더 적은 스크립트를 사용하려고 노력하라.

31. Your PHP scripts are recompiled every time unless the scripts are cached. Install a PHP caching product to typically increase performance by 25-100% by removing compile times.
PHP 스크립트는 캐시되지 않으면 매번 재 컴파일된다. 컴파일 시간을 제거함으로써 25~100%만큼의 성능을 증가시키기 위해 PHP 캐싱 도구를 설치하라.

32. Cache as much as possible. Use memcached - memcached is a high-performance memory object caching system intended to speed up dynamic web applications by alleviating database load. OP code caches are useful so that your script does not have to be compiled on every request
가능한 한 많이 캐시하라. memcached를 사용하라. memcached는 고성능 메모리 객체 캐싱 시스템이다.

33. When working with strings and you need to check that the string is either of a certain length you’d understandably would want to use the strlen() function. This function is pretty quick since it’s operation does not perform any calculation but merely return the already known length of a string available in the zval structure (internal C struct used to store variables in PHP). However because strlen() is a function it is still somewhat slow because the function call requires several operations such as lowercase & hashtable lookup followed by the execution of said function. In some instance you can improve the speed of your code by using an isset() trick.
문자열을 가지고 작업하며 문자열이 특정 길이인지 확인할 필요가 있을 때, strlen() 함수를 쓸 것이다. 이 함수는 계산없이 zval 구조체에서 사용할 수 있는 이미 알려진 문자열 길이를 반환하기 때문에 매우 빠르다. 그러나 strlen()이 함수이기 때문에 여전히 조금 느리다. 왜냐하면 함수 호출은 언급된 함수의 실행 뒤에 lowercase와 hashtable lookup같은 여러 개의 연산을 호출하기 때문이다. 어떤 경우에는 isset() 트릭을 이용하여 코드의 스피드를 증가시킬 수도 있다.

Ex.
if (strlen($foo) < 5) { echo "Foo is too short"; }
vs.
if (!isset($foo{5})) { echo "Foo is too short"; }

Calling isset() happens to be faster then strlen() because unlike strlen(), isset() is a language construct and not a function meaning that it's execution does not require function lookups and lowercase. This means you have virtually no overhead on top of the actual code that determines the string's length.
isset()을 호출하는 것은 strlen()과는 달리 isset()이 언어 기본문법이고 함수가 아니기 때문에 함수 찾와 lowercase 작업을 필요로 하지 않으므로 strlen()보다 더 빠를 수도 있다. 이것은 가상적으로 문자열의 길이를 결정하는 실제 코드에 과부하가 없다는 것을 의미한다.

34. When incrementing or decrementing the value of the variable $i++ happens to be a tad slower then ++$i.
This is something PHP specific and does not apply to other languages,
so don't go modifying your C or Java code thinking it'll suddenly become faster,
it won't. ++$i happens to be faster in PHP because instead of 4 opcodes used for $i++ you only need 3.
Post incrementation actually causes in the creation of a temporary var that is then incremented.
While pre-incrementation increases the original value directly.
This is one of the optimization that opcode optimized like Zend's PHP optimizer.
It is a still a good idea to keep in mind since not all opcode optimizers perform this optimization
and there are plenty of ISPs and servers running without an opcode optimizer.

변수 $i의 값을 증가시키거나 감소키킬 때, $i++은 ++$i보다 조금 더 느릴 수 있다.
이것은 PHP의 특징이고 다른 언어에는 해당되지 않으니 좀 더 빨라질 것을 기대하면서 C나 Java 코드를 바꾸러 가지 마라.
안 빨라질 것이다.
++$i는 PHP에서 좀 더 빠른데 그것은 $i++에 4개의 opcode가 사용되는 대신에 3개만 필요하기 때문이다.
후증가는 사실 증가될 임시변수의 생성을 초래한다.
반면에 전증가는 원래 값을 직접 증가시킨다. 이것은 opcode가 Zend의 PHP optimizer처럼 최적화하는 최적화 기법의 하나이다.
모든 opcode optimizer들이 이 최적화를 수행하는 것은 아니고
많은 ISP와 server들이 opcode optimizer없이 수행되고 있기 때문에 명심하는 게 좋을 것이다.

35. Not everything has to be OOP, often it is too much overhead, each method and object call consumes a lot of memory.
모든 것이 OOP일 필요는 없다. 종종 그것은 너무 많은 과부하가 된다. 각각의 메쏘드와 객체 호출은 메모리를 많이 소비한다.

36. Do not implement every data structure as a class, arrays are useful, too
모든 데이터 구조를 클래스로 구현하지 마라. 배열도 유용하다.

37. Don't split methods too much, think, which code you will really re-use
메쏘드를 너무 많이 분리하지 마라. 어떤 코드를 정말 재사용할지 생각해봐라.

38. You can always split the code of a method later, when needed
항상 메쏘드의 코드를 나중에 필요할 때 분리할 수 있다.

39. Make use of the countless predefined functions
수많은 미리 정의된 함수를 활용해라.

40. If you have very time consuming functions in your code, consider writing them as C extensions
매우 시간을 소비하는 함수가 있다면, C 확장으로 작성하는 것을 고려해봐라.

41. Profile your code. A profiler shows you, which parts of your code consumes how many time. The Xdebug debugger already contains a profiler. Profiling shows you the bottlenecks in overview
당신의 코드를 프로파일해봐라. 프로파일러는 코드의 어떤 부분이 가장 많은 시간을 소비하는지 보여준다. Xdebug 디버거는 이미 프로파일러를 포함하고 있다. 프로파일링은 전체적인 병목을 보여준다.

42. mod_gzip which is available as an Apache module compresses your data on the fly and can reduce the data to transfer up to 80%
Apache 모듈로 사용가능한 mod_gzip은 실행 중에 데이터를 압축하여 전송할 데이터를 80%까지 줄일 수 있다.

PHP5의 새로운 객체지향 모델

New Object Model
PHP 5 에는 새로운 객체 모델이 존재한다. PHP의 객체 조작사항은 더 나은 성능과 보다 많은 특징을 위해 완벽하게 재작성되었다. PHP이전 버전에서 객체는 원시적인 형태로 조작되었다. ( 실례를 들자면 정수나 문자열 같은 것들을 말이다. ). 이 객체 안의 메소드가 가진 결점은 의미론적으로, 어떤 변수가 할당되었거나 파라미터의 값을 메소드로 전달할 때 모든 객체들이 복제된다는 것이었다. 이제 새로운 접근방식에서는 객체가 핸들에 의해 참조되고 값으로 참조되지 않는다. ( 객체식별자와 같은 핸들로 생각할 수 있을 것이다 ).

많은 PHP 프로그래머들은 심지어는 과거의 객체모델이 멋대로 복제되는 것을 눈치채지 못했고 그랬기때문에 PHP어플리케이션의 대부분은 아주 좁은 틀을 벗어나 동작했을 것이다.



Private and Protected Members

PHP 5 는 클래스 프로퍼티의 가시성( 可視性 : visibility )을 정의할 수 있게 하는 private 와 protected 멤버 변수를 도입했다.



Example B-4. Private and Protected Members accesibility

Protected 멤버 변수는 확장된 클래스에서 중복 선언되면 접근할 수 있는데 비해, private 멤버 변수는 단지 멤버 변수를 소유한 클래스에서만 접근이 가능하다.

<?php
class MyClass {
private $Hello = "Hello, World!\n";
protected $Bar = "Hello, Foo!\n";
protected $Foo = "Hello, Bar!\n";

function printHello() {
print "MyClass::printHello() " . $this->Hello;
print "MyClass::printHello() " . $this->Bar;
print "MyClass::printHello() " . $this->Foo;
}
}

class MyClass2 extends MyClass {
protected $Foo;

function printHello() {
MyClass::printHello(); /* Should print */
print "MyClass2::printHello() " . $this->Hello; /* Shouldn't print out anything */
print "MyClass2::printHello() " . $this->Bar; /* Shouldn't print (not declared)*/
print "MyClass2::printHello() " . $this->Foo; /* Should print */
}
}

$obj = new MyClass();
print $obj->Hello; /* Shouldn't print out anything */
print $obj->Bar; /* Shouldn't print out anything */
print $obj->Foo; /* Shouldn't print out anything */
$obj->printHello(); /* Should print */

$obj = new MyClass2();
print $obj->Hello; /* Shouldn't print out anything */
print $obj->Bar; /* Shouldn't print out anything */
print $obj->Foo; /* Shouldn't print out anything */
$obj->printHello();
?>




Private and Protected Methods
PHP 5에서는 또한 private 와 protected 메소드가 도입되었다.



Example B-5. Protected methods example

<?php
class Foo {
private function aPrivateMethod() {
echo "Foo::aPrivateMethod() called.\n";
}

protected function aProtectedMethod() {
echo "Foo::aProtectedMethod() called.\n";
$this->aPrivateMethod();
}
}

class Bar extends Foo {
public function aPublicMethod() {
echo "Bar::aPublicMethod() called.\n";
$this->aProtectedMethod();
}
}

$o = new Bar;
$o->aPublicMethod();
?>


과거의 코드에서는 사용자 정의된 클래스나 함수가 "public", "protected" 또는 "private"를 명기하지 않고 실행했을 것이다.



Abstract Classes and Methods

PHP 5는 또한 추상클래스라는 것과 추상메소드라는 것이 도입되었다. 추상메소드는 단지 메소드의 특징적인 사항을 선언하고 수행사항을 제공하지는 않는다. 다음 예시에서 클래스는 abstract로 선언하는 것을 필요로 하는 추상 메소드를 포함한다.



Example B-6. Abstract class example

<?php
abstract class AbstractClass {
abstract public function test();
}

class ImplementedClass extends AbstractClass {
public function test() {
echo "ImplementedClass::test() called.\n";
}
}

$o = new ImplementedClass;
$o->test();
?>


요약클래스는 명시화될 수 없다. 과거의 코드에서는 사용자 정의된 클래스나 함수에 "abstract"를 명기하지 않고 실행했을 것이다.



Interfaces

PHP 5 에서 interface라는 새로운 객체지향 개념이 도입되었다. 클래스는 인터페이스의 임의의 목록을 수단으로 삼을 것이다.



Example B-7. Interface example

<?php
interface Throwable {
public function getMessage();
}

class MyException implements Throwable {
public function getMessage() {
// ...
}
}
?>


과거에는 사용자정의된 클래스나 함수에 "interface"나 "implements"를 붙이지 않고 실행했을 것이다.



Class Type Hints

느슨한 유형이 남아있는 PHP5는 클래스 타입 힌트를 사용하여 파라미터로부터 메소드로 값을 전달하는 개체의 요청된 클래스를 선언하는 능력을 도입하였다.



Example B-8. Class type hinting example

<?php
interface Foo {
function a(Foo $foo);
}

interface Bar {
function b(Bar $bar);
}

class FooBar implements Foo, Bar {
function a(Foo $foo) {
// ...
}

function b(Bar $bar) {
// ...
}
}

$a = new FooBar;
$b = new FooBar;

$a->a($b);
$a->b($b);
?>


이러한 클래스 타입 힌트는 보통 유형화된 언어에서와 같이 컴파일 할 때에는 체크하지 않는다. 그러나 실행 도중에 체크한다. 이것은 다음을 의미한다:


<?php
function foo(ClassName $object) {
// ...
}
?>




는 다음과 같다 :


<?php
function foo($object) {
if (!($object instanceof ClassName)) {
die("Argument 1 must be an instance of ClassName");
}
}
?>


final
PHP 5 는 최종 멤버와 메소드를 선언하기 위해 "final" 키워드를 도입하였다. final을 붙인 메소드와 멤버는 하위클레스에 의해 오버라이드 되지 않는다.



Example B-9. final method

<?php
class Foo {
final function bar() {
// ...
}
}
?>




이것은 더군다나 최종적인 클래스를 만드는데 가능하다. 이것은 클래스가 특별화 되는 것을 막는다. (다른 클래스에 의해 '절대' 상속될 수 없다.). final 클래스는 자신들의 메소드를 final 로 선언할 필요가 없다.



Example B-10. final class

<?php
final class Foo {
// class definition
}

// the next line is impossible
// class Bork extends Foo {}
?>


프로퍼티는 final 속성을 가질 수 없다..

과거에는 사용자정의된 클래스나 함수에 "final"을 붙이지 않고 실행했을 것이다.



Objects Cloning

PHP 4 에서는 객체가 복제되었을 때 복제된 생성자를 실행하기 위한 결정을 사용자가 할 수 없는 그런 방법을 제공했었다. 복제하는 동안에는 PHP 4 에서는 모든 객체의 프로퍼티에 대한 이상적 복제물을 만들기 위해 비트복사를 하는 단역을 수행하였다.

전체적으로 복제된 프로퍼티와 함께 복제된 객체를 만드는 것은 항상 원하는 행동이 아니다. 생성자 복제를 위해 필요한 것에 대한 좋은 예는 만약 GTK 윈도우를 묘사하는 객체를 소유하고 있고 객체는 이 객체를 복제할때의 GTK 윈도우의 리소스로 유지될 때, 아마 같은 프로퍼티를 가진 새로운 윈도우를 생성하길 원할것이고 새 윈도우의 리소스를 새 객체가 포함하길 원할 것이다. 다른 예로는 만약 객체가 다른 객체를 사용하는 참조자를 붙들어매고 있고, 개발자는 부모객체를 복제할때, 이 다른 객체의 새로운 인스턴스를 생성하길 원할 것이고 그래서 복제된 개체는 그 자신의 분산된 복제물을 가지고 있을 것이다.

복제되는 객체는 clone 키워드를 사용하여 생성된다. ( 가능하다면 객체의 __clone() 메소드를 호출한다 ). 객체의 __clone() 메소드는 직접적으로 호출될 수는 없다.

개발자들이 객체의 새로운 복제물을 생성하기 위해 요청할때, PHP 5 는 __clone() 메소드가 정의 되었는지 아닌지의 여부를 체크할 것이다. 만약 정의되지 않았다면 모든 객체의 프로퍼티를 복제할 기본적인 __clone() 을 호출할 것이다. __clone() 메소드가 정의되었다면 생성된 객체 안에 필요한 프로퍼티를 정할 의무가 있을 것이다. 편의를 위해 엔진은 소스객체로부터 모든 프로퍼티를 임포팅하는 함수를 공급해서 그것들이 소스 오브젝트의 값에 의한 복제물 과 함께 시작할 수 있도록 할 것이고 변경할 필요가 있는 프로퍼티를 단지 오버라이드 할 것이다.



Example B-11. Objects cloning

<?php
class MyCloneable {
static $id = 0;

function MyCloneable() {
$this->id = self::$id++;
}

function __clone() {
$this->address = "New York";
$this->id = self::$id++;
}
}

$obj = new MyCloneable();

$obj->name = "Hello";
$obj->address = "Tel-Aviv";

print $obj->id . "\n";

$obj_cloned = clone $obj;

print $obj_cloned->id . "\n";
print $obj_cloned->name . "\n";
print $obj_cloned->address . "\n";
?>



Constructors
PHP 5 는 개발자로 하여름 클래스를 위해 생성자 메소드를 선언할 수 있게 한다. 생성자 메소드를 가진 클래스들은 새롭게 생성된 객체에서 이 메소드를 초기화 하는데 적당하게 호출해서 객체가 사용되기 전에 필요로 하지 않게 할 것이다.

PHP 4 에서 생성자 메소드는 클래스 자신의 이름과 같은 이름을 가진 클래스 메소드였다. 파생된 클래스로부터 부모 생성자를 호출하는 것이 매우 일반적일 때, PHP 4는 거대한 클래스 계층 주변으로 클래스를 옮기는 성가신 부분을 만들어내는 방법을 택해 작업했다. 만약 클래스가 다른 부모클래스 아래로 귀속하기 위해 옮겨졌을 때, 부모클래스 생성자의 잘 바뀌는 이름과 부모클래스 생성자를 호출하는 파생된 클래스의 코드는 수정될 것이다.

PHP 5 는 __construct()라는 이름으로 불리우는 생성자 메소드를 선언하는 표준방법을 도입하였다.



Example B-12. using new unified constructors

<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}

class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>


이전 버전과의 호환성을 위해 만약 PHP 5 가 주어진 클래스를 위한 __construct() 함수를 찾지 못한다면 클래스의 이름으로 이루어진 이전 방식의 생성자 함수를 찾을 것이다. 효과적으로 이것은 클래스가 __construct() 라는 이름을 가진 메소드를 가진 경우 이것이 다른 의미론을 위해 쓰일것이라는 의미를 가지고 있는데 호환성 문제를 가진 경우에 한해서만 해당한다.

Destructors
객체를 위해 파괴자를 정의하는 능력을 소유하는 것은 매우 유용할 수 있다. 파괴자는 디버깅을 위해, 데이터베이스의 연결을 끊을 때,기타 다른 여러가지 일을 마무리할 때 로그 메세지를 남길 수 있다. PHP 4에선느 객체 파괴자를 위한 기술이 존재하지 않았지만, PHP가 셧다운을 요청하는 도중에 실행될 등록함수를 위해 이미 지원했다.

PHP 5 는 자바와 같은 다른 객체지향언어에서와 유사한 개념을 가진 파괴자를 도입하였다. : 객체의 파괴자를 파괴한 객체가 최종적으로 참조되었을때, 어떤 파라미터 값도 받지 않는 __destruct() 라고 이름 붙여진 클래스 메소드는 메모리에서 객체가 해제되기 전에 호출된다.

Example B-13. Destructor

<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "Destroying " . $this->name . "\n";
}
}

$obj = new MyDestructableClass();
?>


생성자와 같이 부모클래스의 파괴자는 엔진에 의해 명시적으로 호출되지는 않을 것이다. 부모클래스의 파괴자를 실행하기 위해 파생된 클래스에서는 명확하게 파괴자 본문에 parent::__destruct() 를 적어 호출하여야 한다.

Constants
PHP 5 는 완전한 클래스 상수를 도입하였다:

Example B-14. Class constant example

<?php
class Foo {
const constant = "constant";
}

echo "Foo::constant = " . Foo::constant . "\n";
?>


과거에는 사용자정의된 클래스나 함수에 "const"를 붙이지 않고 실행했을 것이다.



Exceptions

PHP 4 는 예외사항 조정에 대한 요소가 없었다. PHP 5 에서는 다른 프로그래밍 언어와 유사한 예외모델을 도입하였다. "catch all"을 위해 지원하지만, "finally"조항을 위한 것이 아님을 주의하여라.

Exception 은 catch 블록에서 다시 제시될 수 있다. 또한 다양한 catch 블록에서 소유하고 있는것도 가능하다. 이러한 경우에서 잡힌 exception 은 꼭대기부터 바닥까지의 각각의 catch 블록의 클래스타입과 비교되고, 'instanceof'를 지닌 첫 블록의 매치는 실행될 것이다. catch 블록이 끝날때 실행사항은 마지막 catch 블록까지 지속된다. 만약 어떤 catch 블록도 'instanceof' 매치를 지니고 있지 않은경우, 그 다음 try/catch block이 다음 try/catch 블록이 존재하지 않고 사용가능하지 않을때까지 검색될 것이다. 이러한 경우 exception 은 exception 절을 발견하지 못하고 프로그램은 예외사항을 보여주면서 중단한다.



Example B-15. Exception creation example

<?php
try {
throw new Exception('Hello');
}
catch (Exception $exception) {
echo $exception;
}
?>


과거에는 사용자정의된 클래스나 함수에 "catch","throw" 또는 "try"를 붙이지 않고 실행했을 것이다.

Dereferencing objects returned from functions
PHP 4 에서는 함수에 의해 반환되는 객체들의 값을 부분참조하기란 불가능했고, 더 이상의 메소드를 만드는 것은 이러한 객체를 호출하였다. PHP 5에서는 다음과 같은 것들이 가능하다 :



Example B-16. Dereferencing example

<?php
class Circle {
function draw() {
print "Circle\n";
}
}

class Square {
function draw() {
print "Square\n";
}
}

function ShapeFactoryMethod($shape) {
switch ($shape) {
case "Circle":
return new Circle();
case "Square":
return new Square();
}
}

ShapeFactoryMethod("Circle")->draw();
ShapeFactoryMethod("Square")->draw();
?>


Static member variables initialization
정적 클래스의 정적 멤버 변수가 이제 초기화될 수 있다.



Example B-17. Static variable initialization example

<?php
class foo {
static $my_static = 5;
public $my_prop = 'bla';
}

print foo::$my_static;
$obj = new foo;
print $obj->my_prop;
?>



Static Methods
PHP 5 는 메소드를 정적으로 선언하기 위해 'static' 키워드를 도입하였다. 그래서 객체의 외부 전후에서 호출할 수 있다.



Example B-18. Static Methods example

<?php
class Foo {
public static function aStaticMethod() {
// ...
}
}

Foo::aStaticMethod();
?>


가상변수 $this 는 static으로 선언된 메소드 안에서는 사용할 수 없다.



instanceof

PHP 5 는 객체가 클래스의 인스턴스건 아니건간에 그것을 조사하고 클래스를 확장하고 인터페이스조건을 제시하게 하기 위한 instanceof 키워드를 도입하였다.



Example B-19. instanceof example

<?php
class baseClass { }

$a = new baseClass;

if ($a instanceof baseClass) {
echo "Hello World";
}
?>



Static function variables
Static은 개발자로 하여금 참조의 방식으로 변수의 값을 상수로 전달하도록 하는 컴파일 도중에 다루어진다. 이러한 변화는 또한 그들의 성능을 엄청나게 향상시켰지만 상수로의 우회적 참조가 더이상의 일을 할 수 없음을 의미한다.



Parameters passed by reference

참조에 의해 함수로 전달된 파라미터값은 아마 이제부터 기본값을 가질 수 있을 것이다.



Example B-20.

<?php
function my_function(&$var = null) {
if ($var === null) {
die("$var needs to have a value");
}
}
?>



__autoload()
__autoload() 요격실행 함수는 선언되지 않은 클래스가 명시화되었을 때, 자동적으로 호출될 것이다. 해당 클래스의 이름은 __autoload() 요격실행 함수로 인자처럼 전달될 것이다.



Example B-21. __autoload() example

<?php
function __autoload($className) {
include_once $className . ".php";
}

$object = new ClassName;
?>



Overloadable Method calls and Property accesses
메소트 호출과 프로퍼티 접근은 __call(), __get() 그리고 __set() 메소드에 의해 오버로드 될 수 있다.



Example B-22. __get() and __set()

<?php
class Setter {
public $n;
public $x = array("a" => 1, "b" => 2, "c" => 3);

function __get($nm) {
print "Getting [$nm]\n";

if (isset($this->x[$nm])) {
$r = $this->x[$nm];
print "Returning: $r\n";
return $r;
} else {
print "Nothing!\n";
}
}

function __set($nm, $val) {
print "Setting [$nm] to $val\n";

if (isset($this->x[$nm])) {
$this->x[$nm] = $val;
print "OK!\n";
} else {
print "Not OK!\n";
}
}
}


$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump($foo);
?>


Example B-23. __get() example

<?php
class Caller {
private $x = array(1, 2, 3);

function __call($m, $a) {
print "Method $m called:\n";
var_dump($a);
return $this->x;
}
}

$foo = new Caller();
$a = $foo->test(1, "2", 3.4, true);
var_dump($a);
?>



Iteration
객체는 아마 foreach와 같은 방식을 사용하였을때의 오버로딩하는 방법으로 반복될 수 있을 것이다. 기본적인 행동은 모든 프로퍼티를 반복한다.



Example B-24. Object iteration example

<?php
class Foo {
public $x = 1;
public $y = 2;
}

$obj = new Foo;

foreach ($obj as $prp_name => $prop_value) {
// using the property
}
?>




인스턴스의 각각의 클래스는 Traversable이라는 빈 인터페이스를 실행할 foreach로 반복될 수 있다. 따가서 적합하게 실행되는 몇몇 객체들은 foreach와 합께 사용될 수 있다.

IteratorAggregate 와 Iterator 인터페이스는 PHP 코드에서 반복사용되는 방법을 상술할 수 있도록 한다. 그것들에 있어 첫번째는 Iterator 인터페이스를 이행하거나 반복가능한 내부 클래스에서 명시회되는 배열이나 객체를 반드시 리턴해야 하는 getIterator() 라는 메소드를 포함한다.



Example B-25. Iterator creation example

<?php
class ObjectIterator implements Iterator {

private $obj;
private $num;

function __construct($obj) {
$this->obj = $obj;
}
function rewind() {
$this->num = 0;
}
function valid() {
return $this->num < $this->obj->max;
}
function key() {
return $this->num;
}
function current() {
switch($this->num) {
case 0: return "1st";
case 1: return "2nd";
case 2: return "3rd";
default: return $this->num."th";
}
}
function next() {
$this->num++;
}
}

class Object implements IteratorAggregate {

public $max = 3;

function getIterator() {
return new ObjectIterator($this);
}
}

$obj = new Object;

// this foreach ...
foreach($obj as $key => $val) {
echo "$key = $val\n";
}

// matches the following 7 lines with the for directive.
$it = $obj->getIterator();
for($it->rewind(); $it->valid(); $it->next()) {
$key = $it->current();
$val = $it->key();
echo "$key = $val\n";
}
unset($it);
?>



__METHOD__ constant
새로운 __METHOD__ 가상 상수는 현재 클래스와 메소드 내부에서 메소드가 사용될 때의 메소드를 보여주고, 클래스 밖에서 사용될때의 함수를 보여준다.



Example B-26. __METHOD__ use example

<?php
class Foo {
function show() {
echo __METHOD__;
}
}

class Bar extends Foo {
}

Foo::show(); // outputs Foo::show
Bar::show(); // outputs Foo::show either since __METHOD__ is
// compile-time evaluated token

function test() {
echo __METHOD__;
}

test(); // outputs test
?>



__toString() method
새로운 __toString() 기술 메소드는 객체를 문자열 변환객체로 오버로드 하도록 한다.



Example B-27. __toString() example

<?php
class Foo {
function __toString() {
return "What ever";
}
}

$obj = new Foo;

echo $obj; // call __toString()
?>



Reflection API
PHP 5 는 재설계한 클래스와 인터페이스, 함수와 메소드를 확장요소들과 같은 기능들을 추가한 완벽한 Reflection API 와 함께 출시되었다.

Reflection API 는 또한 함수와 클래스 그리고 메소드를 위한 도큐먼트 해설을 얻는 방법을 제공한다.

거의 모든 객체지향코드의 외관모습은 개별적으로 상세히 기록된 Reflection API를 사용함에 의해 반영될 수 있다.



Example B-28. Reflection API use example

<?php
class Foo {
public $prop;
function Func($name) {
echo "Hello $name";
}
}

reflectionClass::export('Foo');
reflectionObject::export(new Foo);
reflectionMethod::export('Foo', 'func');
reflectionProperty::export('Foo', 'prop');
reflectionExtension::export('standard');
?>

PHP IDE eclipse

다운로드

PHP eclipse 다운로드 : http://download.eclipse.org/tools/php/downloads/index.php

WebDav/Ftp 다운로드 : http://download.eclipse.org/eclipse/downloads/drops/R-3.2.1-200609210945/ (FTP and WebDAV Support)





Project 관리 기능

생성 및 수정,삭제 등은 너무 쉬워서 스샷을 뜨지 않았습니다.

양해 바랍니다.

Next Only ^^;



기존 에디터에서 FTP 호스트를 기준으로 관리하던 것을

프로젝트 단위로 관리가 가능하기에 편리합니다



나머지 기능은 잘 모르는 관계로 포기 ^^;



저는 프로젝트 단위로 관리 된다는것 자체 만으로도 행복합니다.

FTP 호스트 단위로 관리 하자면 끝도 없지요^^

그리고 FTP 가 끊기면 작업도 불가능하지만 프로젝트 단위로 작업하면 로컬에서도 작업 및 디버깅이 가능합니다.



특히 저가형 호스팅 서버의 경우 ftp 접속자 제한을 많이 걸어 두기에 제한이 걸려 있으면 매번 에디터로 수정하기 힘들었는데

이클립스는 로컬에 파일을 가져와서 자체 컴퓨터에서 작업 하기에 훨씬 편리하고 속도가 빠릅니다.






프로젝트 소스 파일은 자신의 WorkSpace 에 저장되어 지며

해당 소스에 대해서 자체 문법 검사 엔진이 오류 여부를 체크 해 줍니다.

PHP 뿐만 아니라 html 문법 오류까지 검사합니다.



자체 문법 오류를 찾아서 디버깅 하기에 용이 합니다.




메뉴얼 보기 기능



자체 메뉴얼을 내장하고 있어서 함수 이름이 생각나지 않을때 좋네요




리턴 값을 찾을 때도 편리합니다.

이 놈이 string 을 리턴하던가 ㅡ.ㅡ?

명확하지 않은 php function 의 naming 때문에 고민하신적이 있으시죠?



Class 관리 기능




메소드 이름이 기억나지 않아서 고민했었죠 ^^;

매번 Model 파일은 항상 데이터의 즐겨찾기 파일에 두고 자주 사용하지 않는 메소드를 만날때 마다 열어서 보곤 했었는데

이제 그럴 필요가 없어졌습니다.^^





메소드 이름 뿐만 아니라 인자까지 ^^



FTP 기능



새 프로젝트를 만든 다음에 해당 프로젝트에서 우클릭을 하여 Import 메뉴를 이용하면 ftp 를 셋팅하여 소스 파일을 가져올 수 있습니다.

그 이후 Sync 를 맞출 수가 있습니다.

Sync 를 맞춘다는게 어찌 보면 불편해 보일 수도 있지만 자체 디버깅 기능을 가지고 있기 때문에 크게 불편하지는 않습니다.

그리고 요즘은 대부분 Test Server 를 가지고 있잖아요?

설마 아직도 리얼 서버에서 수정하는 용감한 일을 하시는 분은 없으시죠?





이 밖에도 많은데 업무 시간중에 적는거라 여기까지 밖에는....

스마티(Smarty) 템플릿 사용하기

PHP Templating with Smarty




스마티(Smarty) 템플릿 사용하기

김영진(cogolda@hanmail.net)
이 튜토리얼은 http://www.zend.com/zend/tut/tutorial-cezar.php에 있는
내용은 제가 번역, 추가, 생략했습니다.
소스 코드가 많아서 번역할 내용은 많지 않네요.
질문이나, 의견은 메일이나 코멘트 이용해 주시고,
관심있으신 자료 있으시면, 정리해서 올리겠습니다.
이 자료는 제가 스마티 쓸 때 도움이 되었던 문서이기도 합니다.

대상 독자

이 기사는 PHP templating같은 새로운 웹 개발기술을 적용하고 싶은 PHP 프로그래머와 HTML 디자이너를
위해 작성되었습니다.

Smarty 개요

이론적인 웹 개발 과정은 다음과 같다.
처음에는 디자이너가 유저 인터페이스를 만들고, 그것을 프로그래머를 위해 HTML 조각으로 쪼갠 다음
프로그래머가 HTML안에 PHP 비즈니스 로직을 구현하는 것이다.

그것은 이론적으로는 좋다. 그러나 실질적으로, 내 경험을 빌리자면, 클라이언트는 디자인이나 비즈니스 로직을 변경을 자주 요구한다. 그런 일이 일어날 때, HTML은 변경되고 프로그래머는 HTML 소스 코드를 수정한다.

이런 상황에서 문제는 프로그래머는 디자이너가 레이아웃과 HTML 파일을 완성할떄까지 기다려야 한다는 것이다. 다른 문제는 만약 메인 디자인이 바뀌면, 프로그래머는 새로운 페이지에 적합하기 위해 변경할 것이다. 이것이 바로 내가 스마티(Smarty)를 추천하는 이유이다. 스마티는 PHP를 위한 템플릿 엔진이다.

여러분은 http://smarty.php.net/ 에서 스마티 템플릿을 다운로드 할수 있다. 설치 과정은 매우 단순하다. 문서를 읽고 지시에 따라라.

그래서 스마티가 무엇인가? 스마티는 PHP 스크립트로 템플릿을 컴파일하는 PHP 클래스의 집합이다. 스마티는 템플릿 언어이고 디자이너와 프로그래머에게 매우 유용한 툴이다.
(한국에서 디자이너에게 스마티를 가르치는 것이 가능할까요?)

디자이너를 위한 스마티

디자이너 HTML 파일로 작업한다. 스마티와 작업하기 위해, 여러분은 템플릿 파일로 작업한다. 이런 파일들은 정적인 컨텐츠로 완성했으나, 스마티는 마크업 태그와 함께 결합된다.
(여기서 정적인 컨텐츠라는건 php 코드가 없는 html파일을 애기하는 것입니다.
마크업 태그는 페이지 기술 언어 다시말해 html, sgml, xml이런 걸 애기하는 것입니다.)
모든 템플릿 파일은 확장자가 .tpl이다. 스마티 템플릿 태그는 { and } 구획문자로 감싸진다.

웹 페이지의 기본적인 구조를 생각해 보자. 헤더가 있고, 중간 부분이 있고, 꼬리말(footer)이 있다. 헤더와 꼬리말을 포함하는 파일템플릿 파일 다음과 같다.

{include file="header.tpl"}
<form name="form1">
Label1 <input type="text" name="text1">
<input type="submit" value="submit">
</form>
{include file="footer.tpl"}

모든 템플릿은 한 템플릿 디렉토리안에 있어야 한다. 처음에 템플릿을 호출하고 나서, 컴파일된 템플릿은 template_c에 있을 것이다.

스마티 언어는 매우 강력하다. PHP에 모든 변수는 {$Variable_Name}으로 스마티에서 식별된다. 주의할 점은 $ 표시가 앞에 와야 한다. 만약 우리가 PHP에서 $MyName로 호출되는 변수가 있으면, 그 다음에 스마티에서 그것을 출력하기 위해, 우리는 다음과 같이 작성해야 한다.

<html>
<body>
Welcome, {$MyName} <br>
</body>
</html>

스마티의 힘은 유연성에도 있다. 여러분은 템플릿에 IF와 LOOP 삽입할수 있다. IF 문법은 다음과 같다.

{if <condition> }
html code
{else}
html code
{/if}

여러분이 링크가 있는 동적인 메뉴를 가지고 있다고 보자. 여러분이 링크를 클릭하면, 여러분은 특정 페이지에 간다. 그래서 여러분은 PHP에서 정수 변수 $Menu가 있다면, 템플릿은 다음과 같다.

{if ($Menu == 1) }
Option 1
{else}
<a href=”option1.php”>Option 1</a>
{/if}
{if ($Menu == 2 ) }
Option 2
{else}
<a href=”option2.php”>Option 2</a>
{/if}

반복문을 작성하기 위해, 여러분이 PHP에서 다음과 같은 배열을 얻기를 제안한다.
(여기서 얻는다(get)는 표현은 확장자가 php인 파일에 있는 변수나 배열을
템플릿 파일이 가져와야 하기 때문에 이렇게 표현한 것입니다.)

<table>
<tr
{section name=user loop=$userID}
{if $smarty.section.user.iteration is odd}
bgcolor=#efefef
{else}
bgcolor=#ffffff
{/if}
>
<td> ID = {$userID[user]} </td>
<td> Name = {$name[user]} </td>
<td> Address = {$address[user]} </td>
</tr>
{sectionelse}
<tr>
<td>
There is no user.
</td>
</tr>
</section>
</table>

반복자는 스마티를 위한 내부 카운터이다. 그것은 우리에게 섹션의 현제 반복을 알게 해준다. 필자는 만약 현제 반복 변수가 남는지 아닌지 확인으로 인해 테이블에서 다른 열 색깔을 만들기 위해 내부 변수를 사용한다.(뭔 소리를 하는 건지)

LOOPS에 대안은 단일 연관 배열을 반복하기 위해 사용되는 FOREACH이다.

<foreach from=$users item=current_user>
Name = {$current_user}
<foreachelse}
No user available.
</foreach>

SECTION과 FOREACH의 중요한 차이는 SECTION은 특정 변수에서 시작할 수 있고, 반복을 위해 스텝을 설정할수 있다. 그에 반해 FOREACH는 모든 변수에 대해 반복할 수 있다.
(뒤에 예제 나오니까 그거 보시면 이해하실수 있을 것입니다.)

프로그래머를 위한 스마티

프로그래머를 위한 장점은 그들은 HTML과 PHP 코드를 분리할 수 있다는 것이다. 좀더 자세히 말하자면, 만약 디자이너가 페이지의 레이아웃을 바꾸면, 프로그래머는 기능적으로 바뀌지 않았다면, 새로운 레이아웃에 적합하게 하기 위해 코드를 바꿀 필요가 없다. 여러분은 여러분의 파일에서 작업하고 화면에 출력되는 모든 변수를 템플릿에 할당하고, 맥주 마시러 나간다.. 디자이너는 레이아웃을 바꾸고 내부적인 에러를 해결하기 위해, 여러분에게 전화 걸고 싶지 않을 것이다.
(쉽게 설명 하자면, 디자이너가 화면 디자인을 살짝 바꾼다음에 프로그래머에게 좀 고쳐달라고 말하지 않아도 됩니다. 여러분이 하는 일은 비즈니스 로직 구현이니까요)

PHP 파일에서 여러분은 스마티 클래스 require ‘Smarty.class.php’를 포함해야 한다.
그리고 $smarty = new Smarty로 인스턴스를 만들어야 합니다.

템플릿에 변수를 할당하기 위해, 여러분은 다음과 같이 해야 한다.
$smarty->assign(‘UserName’, ‘John Doe’).
모두 끝난 다음 여러분은 템플릿 $smarty->display(‘index.tpl)을 보여주기 위해 메소드를 호출한다.

다음과 같은 소스 코드를 보자 (index.php)


<?php
require 'Smarty.class.php';
$smarty = new Smarty;

$smarty->assign('Username', 'John Doe');
$smarty->display('index.tpl');
?>

이런 템플릿(index.tpl)을 보자.


<html>
<body>
Welcome {$Username}
</body>
</html>

여러분은 역시 PHP에서 템플릿에 그것을 통과하는 배열을 만들수 있다.


$tmp = array ( 'UID'=> '10', &'Name' => 'John Doe', 'Address'=>'Home address');
$smarty->assign('info', $tmp);

샘플 스크립트 ( 위의 내용은 추상적으로 설명한거고 밑에 내용이 중요합니다.)

이 스크립트는 로컬 데이터베이스에 접속하고 ‘Products’ 테이블에서 모든 제품을 선택(select)한다. 그 때 템플릿에 모든 변수를 통과한다. 그것은 스크린에 그것을 출력한다.


INDEX.PHP

<?php
// 스마티 클래스 파일 포함
require 'Smarty.class.php';
// 스마티 인스턴스 생성
$smarty = new Smarty;
// 디비 설정, 이부분은 각자에 맞게 고치십시오
$hostname = "localhost";
$dbUser = "sqluser";
$dbPass = "sqlpass";
$dbName = "sqldb";
// 데이터베이스에 접속
$conn = mysql_connect($hostname, $dbUser, $dbPass) or die("Cannot connect to the database");
// 디비 선택
mysql_select_db($dbName);
// 질의문 저장
$sql = "SELECT prodID, info FROM products ORDER BY prodID ASC";
// 테이블에서 모든 제품을 선택하라.
$res = mysql_query($sql);
// results를 배열 변수로 선언
$results = array();
$i=0;
while ($r=mysql_fetch_array($res)) {
$tmp = array(
'prodID' => $r['prodID'],
'info'=> $r['info']
);
$results[$i++] = $tmp;
}
// 결과를 템플릿에 넘긴다
$smarty->assign('results', $results);
// 템플릿 파일을 로딩load 한다
$smarty->display('index.tpl');
?>


INDEX.TPL

<html>
<body>
Here's a table with the results: <br>
<table cellpadding=1 cellspacing=0 border=0 width=100%>
{section name=nr loop=$results}
<tr {if $smarty.section.nr.iteration is odd} bgcolor="#efefef"{/if}>
<td class=fb width=15%>
<nobr><a href=”show-product.php?id={$results[nr].prodID}">Press here</a>

<td class=fb width=29%><a href="show.php?id={$results[nr].prodID}"
{popup inarray=$smarty.section.nr.iteration}
>{$results[nr].info}</a></td>
</tr>

{sectionelse}
<tr><td align="center"><br><b>no product </b> <br> </td></tr>
{/section}

</table>

<br>

Here's a select with the results: <br>
<select name="mys">
{section name=nr loop=$results}
<option value="{$results[nr].prodID}">{$results[nr].info}</option>
{/section}
</select>

</body>
</html>


요약

스마티는 디자이너와 개발자 둘 다 에게 멋진 툴이다. 스마티를 사용하면서, 여러분은 사이트 개발과 관리 시간을 줄일 수 있다. 만약 여러분이 개발자라면, 여러분은 더 이상 HTML 코드로 뒤섞인 PHP code가 필요하지 않다. 비즈니스 로직에만 집중하고 디자이너에게 HTML을 떠나라.

PHP 보안 ! tood.net

이 요약은 사용할 수 없습니다. 이 글을 보려면 여기를 클릭하세요.

PHP5에서의 객체지향프로그래밍

PHP4에서는 문법적으로만 객체지향프로그래밍 지원했다고 한다면 PHP5에서는 개념적, 구조적으로 객체지향적 프로그래밍을 지원하게 되었다.



-





1. 멤버접근 제한자



접근제한자 의미
private 해당 클래스 내에서만 접근 가능
protected 해당 클래스 및 자식클래스에서만 접근가능
public 모든 클래스에서 접근 가능




2. This 참조



클래스 정의 후 인스턴스를 생성한다.

이때 생성된 인스턴스의 멤버변수나 함수를 지칭하거나 호출할 때마다 클래스이름을 이용하여 호출할 경우 프로그램의 변환가능성이나 사용성이 현저히 떨어질 것이다.

이때 사용하는 것이 범용성이 높은 This참조이다.



public function setTime($hour, $minute,$second){

$this->hour=$hour;

$Time->minute=$minute;

...



3. 인스턴스 생성,소멸, 입력값 체크



인스턴스 생성과 소멸 시 초기값 입력이나 입력값 체크를 하려할 경우가 많을 것이다. 이때마다 초기값 입력이나 입력값 체크를 하는 함수를 만든다면 비효율적일 것이다. 이때 생성



<?

class Time {

private $hour;

private $minute;

private $second;



function __construct($hour,$minute,$second) // 인스턴스 생성 시 무조건 자동호출되는 메소드

// 초기값 자동세팅 기능으로도 활용할 수 있음

{

$this->setTime($hour,$minute,$second);

}



function __distruct()

{

echo "소멸자 호출!\n";

}



public function setTime($hour,$minute,$second)

{

$this->hour=$hour;

$this->minute=$minute;

$this->second=$second;

}



/*



public function setTime($hour,$minute,$second){ // 객체인스턴스 메소드 입력값 체크해주는 로직

{

$this->hour=($hour>=0&&$hour<24) ? $hour:0;

$this->minute=($minute>=0&&$minute<60) ? $minute:0;

$this->second=($second>=0&&$second<10) ? $second:0;

}



*/



public function ToUniversalTime()

{

return sprintf("%02d:%02d:%02d",$this->hour,$this->minute,$this->second);

}



}



$time = new Time(22,57,38); // 초기값을 인스턴스 생성 요청



// $time = NULL; //요렇게 NULL값입력하면 객체강제소멸되며 아래 객체참조부분 에러발생



echo $time->ToUniversalTime();



?>





4. __set(), __get() 메소드



클래스 정의 시 정의된 멤버변수외에 다른 멤버에 값을 할당하거나 참조할 때 자동으로 호출되는 메소드.

캡슐화에 활용되므로 .. 객체지향적 프로그래밍을 지원하는데 중요한 메소드임.



<?

class Time {

private $data;



function __construct ($hour,$minute,$second) { // 최초 인스턴스 생성 시 setTime 메소드 호출

$this->setTime($hour,$minute,$second);

}



function __get($name) { // 정의되지 않은 멤버값을 참조할 때 호출. 배열변수 data 값 참조

return isset($this->data[$name]) ? this->data[$name] :NULL;

}



function __set($name,$value) { // 정의되지 않은 멤버값 할당할 때 호출.

if(in_array($name,array("hour","minute","second"))) { //인자'name','value'가 배열변수라면

if(!strcmp($name,"hour"))

$value = ($value>=0 && $value<24) ? $value :0;

else

$value = ($value >=0 && $value <60) ? $value : 0;



$this->data[$name] = $value;

}

}



public function setTime ($hour,$minute,$second) { // 정의되지 않은 멤버값 호출

// __set 메소드 호출

$this->hour=$hour;

$this->minute=$minute;

$this->second=$second;

}



public function ToUniversalTime() {

return sprintf("%02d:%02d:%02d",$this->hour,$this->minute,$this->second);

}



public function ToStandardTime() {

return sprintf("%02d:%02d:%02d%s",(($this->hour%12==00)?12:$this->hour%12),$this->minute,$this->second,($this->hour<12?"AM":"PM"));

}

}



$time = new Time (22,57,38); // __construct 메소드 호출



echo $time->ToUniversalTime()."<br>"

echo $time->ToStandardTime();



?>





5. __toString() 메소드



인스턴스의 현재 상태나 모습을 그대로 나타내야 할 경우가 있다.
이때 문자열 형태로 인스턴스의 상태나 모습을 그대로 출력해 주는 예약된 메소드가 __toString() 메소드이다.
(자바나 C#의 toString() 메소드와 같은 역할 수행)

메소드의 실제기능은 사용자가 재정의하나 호출은 사용자가 해당 클래스의 인스턴스를 echo, print()과 같은 문자열 출력 메소드를 이용하여 출력하려고 하면 자동으로 호출진다.



[샘플]

<?

class Time {

...

function __toString() {
return "Time :".$this->ToUniversalTime();
}

$time = new Time(22,33,44);
echo $time; // 인스턴스 생성
// Time : 22:33:44 출력
echo new Time(13,23,43); // 위와 동일결과 출력
echo "결과 =>".$time; // 인스턴스 생성되었으나
// '.' 연산자 기능먼저수행
// '결과 => Object id#1' 출력
echo "결과 =>",$time; // 연결연산기능과 문자열표현을 다 이용하려면
// ',' 연산자 사용
// '결과 => Time : 13:23:43' 출력됨
echo (string) $time; // 'Object id#1' 출력

?>



6. Type hinting



PHP에서는 Java나 C#에서처럼 명시적인 타입정의를 통해 타입제약을 엄격하게 적용하고 있지 않다.
그러나, PHP에서도 함수나 메소드를 정의할 때 인자가 클래스의 인스턴스를 변수형으로 가질 경우 해당 인자앞에 변수형인 인스턴스의 클래스 이름을 명시할 수 있다.
이렇게 인자의 타입을 정의하면 타입이 정의한 클래스로 한정된다.



Type hinting기능을 사용 하지 않을 경우 일일이 해당 인자값을 검사하는 루틴을 중간에 삽입해야 함.



[샘플]



<?

class Date
{
private $year;
private $month;
private $day;

function __construct($year,$month,$day)
{
if(checkdate($month,$day,$year))
{
$this->year=$year;
$this->month=$month;
$this->day=$day;
}
else
{
die ("wrong date data");
}
}

function toUniversalDate()
{
return sprintf("%04d/%02d/%02d",$this->year,$this->month,$this->day);
}
};

class Employee
{
private $firstName;
private $lastName;
private $birthDate;

function __construct($firstName,$lastName,Date $birthDate)
{
$this->firstName=$firstName;
$this->lastName=$lastName;
$this->birthDate=$birthDate;
}

public function getBirthDate()
{
return $this->birthDate;
}

public function __toString()
{
return "Employee:".$this->lastName."".$this->firstName."[".$this->birthDate->toUniversalDate()."] <br>";
}

};

$employee = new Employee ("Gil","Gong",new Date(1990,01,21));
$employee = new Employee ("Gil","Gong","1990/01/21"); // __construct 함수에 Date 클래스형태로 인자값 지정
// 에러 발생함
//Fatal error: Argument 3 passed to Employee
echo $employee,"\n";
echo $employee->getBirthDate()->toUniversalDate(); // PHP5에서 본격적으로 지원되는 객체에서 또 다른 객체 참조

?>



7. 정적 클래스 멤버



하나의 객체에서 생성된 인스턴스가 공통적으로 영향을 미쳐야 하는 한 멤버변수가 있을 경우 이를 정적 클래스 멤버변수로 정의해서 사용한다.

예를 들어 인스턴스 Book01, Book02 를 가진 Book 클래스의 총출판권수 정보가 필요할 경우 이를 클래스 수준에서 다루어 정적 클래스 멤버변수로 정의한다.



"클래스이름 ::"의 형태로 접근한다.



[샘플]



<?

class Book

{

public static $count = 0;

private $title;

...



function __construct ($title,$price)

{

++Book::$count;

...

}

}

...

book1 = new Book("War wolf","10000");

echo "클래스 생성 후 책 수량 :".Book::$count."<br>";

...

?>



정적 클래스 멤버함수도 동일하게 사용된다.





8. 클래스 상속



- 파일참조를 통한 클래스 참조



<?



if(!class_exists("Book"))

{

include_once "class.book.php";

}

...



?>



- 클래스 상속



<?

class Magazine extends Book

{

...

}

?>



이때 부모클래스의 Private 멤버변수는 하위클래스에서도 접근할 수 없으므로 종종 원치않는 결과가 나온다. 이때는 Protected 접근권한으로 부모클래스 멤버변수를 정의한다.



9. 의미는 있지만 직접적 구현이 필요치 않은 중간매체적 클래스, 추상클래스 (abstract class)



추상클래스로 부터 바로 인스턴스를 생성할 수는 없으며, 반드시 추상클래스를 상속받은 구체클래스(Concrete class)로 부터 인스턴스를 생성해야 한다.



이때, 모든 메소드가 추상메소드로만 정의된 클래스를 인터페이스(interface)라고 한다.



<?

interface Shape

{

public abstract function getArea();

public abstract function getVolume();

}

?>



<?

...

class Point implements Shape

{

...

}

?>



인터페이스를 통한 다중상속의 효과



class D extends C implements A, B {...}





10. 아주 유용한.. ^^ 클래스 파일을 자동으로 찾아서 로딩해줄 수 있는 __autoload() 메소드



<?

function __autoload($class)

{

require_once "class.".$class."php"; // 단, 클래스를 'class.data.php' 와 같이

// 미리 파일로 분리해 두어야 함

}



echo new Magazine(22); // Magazine 클래스가 없으므로 __autoload() 메소드를 호출

echo "<br>";

echo new Book(22);

echo "<br>";

echo new Books(22);

echo "<br>";

echo new Article(23);

echo "<br>";

?>



cf. 실수로 클래스에서 정의되지 않은 메소드를 호출하였을 경우 어떤 메소드가 미리 정의되지 않았는가 볼려면 __call() 메소드를 이용하면 된다.



__call ($method, $parameter)

{

}

의 형태로 자동호출하면 된다.





■■■■■ 예외처리 (Exception Handling) ■■■■■■





1. try / catch / throw



<?



try {

throw new Exception ("예외가 발생하였습니다!"); //예외가 발생할 수 있는 코드

}



catch (Exception $exception) // 예외가 발생했을 때의 에러처리 코드

{

echo "발생사유 : ".$exception->getMessage()."(Error Code :".$exception->getCode().")<br>;

echo "발생위치 : ".$exception->getLine()."라인".$exception->getFile()."파일<br>";

}

?>



위 내용은 PHP5에서 제공하는 기본예외클래스인 Exception 클래스를 사용한 예이며, 개발자가 직접 예외클래스를 만들 수도 있다.



<?

class FileIOException extends Exception

{

function __construc($message)

{

$this->message=$message;

}

};



try

{

if(!$fp = @fopen("unknown .txt","r"))

throw new FileIOException ("지정하신 파일을 찾을 수 없습니다.");

}

catch (FileIOException $exception)

{

echo $exception->getMessage()."<br>";

echo $exception->getCode()."<br>";

echo $exception->getFile()."<br>";

echo $exception->getLine()."<br>";

echo $exception->getTraceAsString."<br>";

}

?>