2007년 7월 31일 화요일

남대문 가츠라~

명동의 가쓰라하고는 다른 곳(?)입니다. 체인점이라고 합니다. (베이즐 님의 블로그)
사용자 삽입 이미지

가츠라~


사용자 삽입 이미지

히레까스랑 닭 튀김(이름이 생각이 안나네요 ^^;;)이랑 장어구이(^^;;; 어찌하다 시켰답니다.)를 시켜서 먹었는데....
사용자 삽입 이미지

사용자 삽입 이미지

장어구이는 튀김하고 같이 먹기에는 좀.. 별로인 듯하군요. 튀김 굳~


튀김이 최고네요. 튀김옷이 고기에 쫘~ㄱ 달라 붙어서 입안에 들어갈 때는 살살 녹는듯한 그맛~
사용자 삽입 이미지

오늘의 주인공 히레까스~


사용자 삽입 이미지

닭을 튀긴건데.. 이름은 기억이 안나네요 ^^;;


아~ 오랜만에 먹어본 황홀한 튀김의 재맛을 느꼈다고 할까나요~
사용자 삽입 이미지
사용자 삽입 이미지

야근한다고 저녁 때 먹으러가서 폰으로 찍은 사진밖에 없습니다.
※ 모듬튀김이 메뉴에서보면 작아보이는데 의외로 양이 많습니다..  -_-b

사용자 삽입 이미지

위치는 숭례문쪽의 파란 화살표 부근에 있습니다. ^^

※※ 보다보니... 명동의 가츠라도 체인점인 것 같네요.
※※※  남대문 가츠라 링크입니다. 메뉴도 포함되어 있네요.

2007년 7월 29일 일요일

SimpleTest(Unit Testing for PHP)

SimpleTest는 PHP에서 사용할 수 있는 Unit Testing 툴로서 이클립스 플러그인으로 사용할 수 있습니다.

설치하는 방법
  1. SimpleTest에서 이클립스 플러그인을 다운로드 받습니다.
  2. 적당한 장소에 다운로드 받은 소스의 압축을 풉니다.
  3. 이클립스를 실행시킨 다음에 Help > Software Updates > Find and install을 실행합니다.
  4. Search for new features to install > New Local Site을 클릭해서 설치할 프로그램의 위치를 설정합니다.

    사용자 삽입 이미지

  5. Finish를 눌러서 설치를 합니다. (설치가 완료된 후에 이클립스가 재시작됩니다.)
  6. 재시작한 이클립스에서 Window > Preferences를 클릭해서 Preferences 다이얼로그를 띄웁니다.
  7. SimpleTest항목을 찾은 다음에 PHP.exe file의 위치와 php.ini 파일의 위치, 그리고 Test File Suffix를 설정해줍니다. (Suffix를 설정하면 플러그인이 테스트 파일을 찾는데 도움을 줍니다. - 저의 경우에는 .test.php로 설정하였습니다.)
    사용자 삽입 이미지

  8. OK를 눌러서 창을 닫습니다.
사용하는 방법
PHP파일을 생성한 후 UnitTestCase를 상속받은 테스트 클래스를 작성해주면 됩니다. 테스트할 메소드는 test로 시작하여야만 됩니다.
<?php
    class test1 extends UnitTestCase {
        function test_pass(){
            $x = 1;
            $y = 2;
            $total = $x + $y;
            // 기대하는 결과값인 3과 메소드의 수행결과인 $total을 비교하여 비교치가
             // 다른 경우 세 번째 argument를 test fail과 함께 출력하게 됩니다.
            $this->assertEqual(3,$total, "This should pass");
        }
    }
?>
작성한 파일을 실행하기는 간단합니다. Run > Open Run Dialog를 띄운 다음에 SimpleTest를 실행시켜주거나 실행할 파일을 설정한 후 실행시켜주면됩니다.
사용자 삽입 이미지

※ 테스트를 추가하는 방법도 간단합니다. UnitTestCase를 상속받은 클래스에서 test...()를 추가하거나 UnitTestCase를 상속받는 테스트 클래스를 추가한 후 GroupTest를 생성하여 테스트가 가능합니다.
<?php
    class myGroupTest extends GroupTest {
        function myGroupTest() {
            parent::GroupTest('');
            $this->addTestFile(dirname(__FILE__).'/test1.php');
            $this->addTestFile(dirname(__FILE__).'/test2.php');
        }
    }
?>
※※ setUp() 메소드와 tearDown() 메소드를 사용하여 테스트 클래스가 로딩하기 전에 실행되는 작업을 수행하고, 테스트 종료한 다음에 마무리 작업을 수행할 수 있습니다. (다른 단위 테스트와 동일합니다.)

※※※ Mockup 생성도 가능합니다. Mockup을 생성하는 목적은 내부와 외부를 연결해주는 게이트웨이에 해당하는 부분을 만들 때 사용합니다.
// mock_objects를 포함시킵니다.
require_once('simpletest/mock_objects.php');

// Mockup으로 만들 클래스 파일이 따로 있다면 require_once를 호출하여 포함시킵니다.
// 또는 클래스를 동일 테스트 파일에 선언해줍니다. (인터페이스만 선언해주면 됩니다.)
...
// Mock 클래스를 생성합니다.
Mock::generate('Sample');

// 이렇게 생성된 Mock 클래스는 Mock~으로 시작되는 이름의 클래스로 생성할 수 있습니다.
sample = new MockSample();

// 생성된 클래스의 메소드가 호출될 때의 동작을 정의하기 위해서 expect
// 또는 setReturnReference() 를 사용하여서 어떤 메소드가 호출될 때 어떤
// 리턴결과가 돌아올지에 대해서 정의가 가능합니다.
sample->expect(...);
출처 :  SimpleTest  via Manning, PHP in Action(Objects, Design, Agility)- 9,10장

※ SimpleTest의 API는 여기로 -> http://simpletest.org/api/

6. Object-oriented pinciples

1. The open-closed principle(OCP)
확장에는 열려있고, 수정에는 닫쳐있어야 한다.(open to extension, closed to modification)
// 수정전
function hello() {
   echo "Hello, Dolly!\n";
}

// 수정 후, 변경 가능한 요소인 이름을 인자로 받아 출력, 코드 수정없이 출력 범위를 확장함
function hello($name) {
   echo "Hello, ".$name."!";
}
2. The single-responsibility principle(SRP)
하나의 클래스에는 하나의 책임만을 져야한다. (변화 가능한 요소가 하나만 있어야 한다. -A class should have only one reason to change)

템플릿 엔진(Template engine)의 기본적인 특징은 다음과 같습니다.
  • 변수들의 집합을 저장할 수 있어야 합니다. (Storing a set of variables)
  • 템플릿 파일을 읽을 수 있어야 합니다. (Reading a template file)
  • 템플릿 파일과 변수 집합을 통하여 출력물을 생성할 수 있어야 합니다. (Combining the first two to generate output)
이러한 특징을 바탕으로 Template을 생성하면 다음과 같은 클래스를 만들 수 있을 것입니다.
class Template {
   private $vars;
   private $file;

   // 생성자에서 파일을 인자로 받아서 템플릿 파일에 사용될 파일을 저장합니다.
   public function __construct($file) {
     $this->$file = $file;
   }

   // 이름과 값 쌍으로 받아서 변수를 저장합니다.
   public function set($var, $value) {
     $this->vars[$var] = $value;
   }
  
   /* HTML로 출력합니다.
    * 1. 설정된 변수들의 집합을 현재의 심볼로 임포트합니다.
    * 2. 출력 버퍼에 템플릿 파일을 출력합니다.
    * 3. 출력 버퍼의 내용을 $string으로 리턴한 다음에 버퍼를 끕니다.
    * 4. 출력 버퍼를 클리어한다음 $string을 리턴합니다.
    */
   public function asHtml() {
     extract($this->vars);
     ob_start();
     include $this->file;
     $string = ob_get_contents();
     ob_end_clean();
     return $string;
   }
}
(관점에 따라 다를 수 있습니다만,) SRP의 원칙에서 봤을 때는 변수를 저장하는 부분과 템플릿 파일을 읽어들이는 부분과 템플릿으로 생성하는 부분 세 개의 책임을 가지는 클래스로 볼 수 있습니다. 따라서 이들을 분리할 수도 있겠죠.
// File을 읽어들이고 처리하는 클래스입니다.
class File {
   public function __construct($name) {
     $this->name = $name;
   }
   // File의 내용을 스트링으로 리턴합니다.
   function getContents() {
     return file_get_contents($this->name);
   }
}

// Template에서 사용하기 위한 변수들을 설정합니다.
// 디폴트 값을 설정하는 기능을 여기에서 할 수 있겠죠.
class TemplateData {
   private $vars;
   public function set($var, $value) {
     $this->vars[$var] = $value;
   }
   public function getArray() {
     return $this->vars;
   }
}

// TemplateData와 File에 템플릿 변수/파일을 처리하는 기능을 위임한 클래스입니다.
class Template {
   private $data;
   private $file;

   public function __construct($file) {
     $this->file = new File($file);
     $this->data = new TemplateData;
   }

   public function set($var, $value) {
     $this->data->set($var, $value);
   }

   private function processTemplate() {
     extract($this->data->getArray());
     $string = $this->file->getContents();
    // 파일처리와 템플릿 생성을 분리하여 include를 사용할  수 없어서 eval을 사용
     eval('?>'.$string);
   }

   public function asHtml() {
     ob_start();
     $this->processTemplate();
     $string = ob_get_contents();
     ob_end_clean();
     return $string;
   }
}
※ 그 외에도 The Dependency-inversion principle(DIP)와 Layered designs가 소개되어있는데 생략합니다~
※※ 4,5 장도 읽어봤는데.. 아는 내용이라 생략합니다~ ^^;;;

출처: Manning, PHP in Action(Objects, Design, Agility) 보면서 요약한 내용입니다.

여행 유의·자제·제한·금지 지역 보기

'여행 유의·자제·제한·금지 지역'에 대한 정보는 외교통상부 해외안전여행사이트가 원 출처더군요.

사용자 삽입 이미지
최소한 기사가 정보의 전달이 목적이라면 원래 출처와 링크를 명확하게 표기를 해줬으면 좋겠네요.
인터넷 상에서의 글쓰기의 기본 아닐런지...

출처: 외교통상부 해외안전여행사이트 via 중앙일보 이지은 기자의 '의외로 많은 여행 유의·자제·제한·금지 지역'

※ 태국이 여행유의,제한지역으로 되어있던데... 쓰레기 만두에 불량식품천국인 중국도 여행유의 지역에 들어가야 하지 않을까 생각이 되네요. ^^

2007년 7월 24일 화요일

3. Using PHP classes effectively

1. visibility: 메소드나 프로퍼티에 대해서 접근 권한 설정이 가능합니다.
  • public
  • private
  • protected - 디폴트로 설정됩니다. 부모나 자식 클래스에서만 접근이 가능합니다.
2. getter/setter 메소드 __get()__set()를 사용하여 접근 메소드를 만들면 getProperty()나 setProperty() 메소드 같은 메소드를 만들 필요없이 다음과 같은 형태로 사용할 수 있습니다.
$ClassInstance->property;
※ getter/setter의 경우 실험적으로 도입된 성격이 강하다고 합니다.

3. final - 자식 클래스에서 클래스 또는 메소드의 오버라이딩을 막습니다. (deprecated를 나타내기 위해서 사용할 수 있습니다.)

4. ::(double colon)은 클래스의 변수, 메소드 또는 상수를 접근하기 위해서 사용됩니다.
$product = Product::find($productCode);
5. 클래스 메소드는 static을 사용하여 정의합니다.
static public function encryptPassword(...){}
클래스 밖에서는 ::를 사용하여 접근하나 클래스안에서는 self를 사용하여 접근이 가능합니다.
self::encryptPassword();
※ 클래스 메소드, 변수에 대한 접근은 $this를 사용할 수가 없습니다.
※※ 언제 클래스 메소드를 사용하는가?
  • Creation methods and factory methods
  • Finder methods
  • Procedural code
  • Replacement for constants
6. 상수(constant)는 const로 정의합니다. 상수를 정의할 때는 $를 사용하지 않습니다.

7. abatract 선언을 사용할 수 있습니다.
  • abstract로 정의된 클래스 또는 메소드를 바로 사용할 때 에러가 발생합니다.
  • abstract로 정의된 메소드가 포함되어 있는 클래스는 abstract 클래스가 되어야 합니다.
abstract class HtmlDocument{
    public function getHtml() {...}
    abstract public function getContent();
}
8. CLASS Type Hints, 인자로 넘어오는 파라미터의 타입을 체크할 수 있습니다.
public function addDocument(Document $document) {}
  • Documnet의 인스턴스 또는 이를 상속받은 클래스의 인스턴스의 경우 정상통과가 되나 문자열(string)이나 다른 객체(Object)를 통과시킬 때 경고(Warning)을 발생시킵니다.
  • 그러나, 통과된 후에Document에 정의되어 있지 않은 메소드를 호출해도 에러메시지가 발생하지는 않습니다.
  • 객체들과 배열들만 체크가 가능하며 일반적인 데이타 타입(plain data type)을 체크하지는 않습니다.(예를 들면 문자열)
  • Type Hint의 단점으로는 체크를 위해 사용된 클래스가 변경되는 경우 관련된 Type Hint를 모두 변경해줘야 하는 의존(dependency)이 생긴다는 점입니다.
  • Type Hint가 실패한 경우 nonExistentmethod()가 호출됩니다.
9. instanceof를 사용해서 타입 체크가 가능합니다.
public function addDocument($document) {
    if(!($document instanceof Document)) {
        ...
    }
}
10. 인터페이스(interface)
interface Template {
   public function __constuct();
   public function execute();
   ...
}
자바의 인터페이스와 비슷합니다.
  • 클래스는 여러 인터페이스를 동시에 구현하는 것이 가능합니다 .
  • 동적언어에서는 인터페이스가 없는 것과 반대로 php에서는 이를 지원합니다.
    • 생성비용으로는 인터페이스 파일을 여는 비용을 제외하고는 거의 없습니다.
    • 디자인을 좀 더 명확하게 나타내고 실수를 막을 수 있습니다.
  • abstract와 동일한 역할을 합니다.
  • 두 개의 인터페이스를 구현하는 경우, 각각의 인터페이스가 동일한 메소드를 갖지 못합니다.
  • 인터페이스는 다른 인터페이스를 상속할 수 있습니다.
  • 생성자(__construct())를 인터페이스에서 선언할 수 있습니다.)
클래스에서 인터페이스를 구현하도록 선언하는 것도 비슷합니다.
class SmartyTemplate implements Template()
출처: Manning, PHP in Action(Objects, Design, Agility) 보면서 요약한 내용입니다.

2. Objects in PHP

1. PHP5에 들어오면서 객체 지향적 설계가 가능하게 되었습니다.

2. PHP 클래스 형태
// 상속은 extends를 사용합니다.
class HelloWorld extends ParentClass{
       
private $world;
       
public $hello;
       
       
// 생성자입니다.
       
function __construct($world) {
               
// 자신의 프로퍼티나 메소드를 호출하는 경우 $this를 사용합니다.  
                $this
->world = $world;

               
// 부모의 생성자를 호출할 때는 parent를 사용할 수 있습니다.
                parent
::__construct();
       
}
       
       
function getHtml() {
               
return "Hello, ".$this->world."!";
       
}
}
3. PHP4와 달리 객체를 나타낼 때 레퍼런스를 사용합니다. PHP4에서 &를 사용하여 레퍼런스를 지정할 수 있어나 내부에서 symbol table alias를 가지고 있습니다.

4. 메소드의 Override를 지원합니다.

5. 기존에 exception이 발생하는 경우 die()를 사용하여 처리했습니다. PHP5에서는 throw를 사용하여 Exception을 발생시킬 수 있고,
throw new Exception('...');
try/catch를 사용하여 Exception을 잡을 수 있습니다.
try {
   ...
}catch(Exception $e) {
   print($e->getMessage());
}
6. 디버깅하는 경우 스택을 따라가고 싶을 때 debug_trace()와 debug_print_backtrace()를 사용할 수 있습니다.

7. 예외를 사용하는 것보다는 예외 상황에서 이를 처리하는 코드를 사용하는것이 더 좋습니다.

8. 사용자 정의 예외도 만들 수 있습니다. 그러나, 사용자 정의 예외는 최대 5~7개정도가 좋으며 내부에서 예외를 구분하는 코드를 사용하는 편이 더 낳습니다.
class UserException extends Exception{}
9. PHP에서 제공하는 예외를 사용자 정의로 바꾸는 것도 가능합니다.
class ErrorFromPHPException extends Exception{}
function PHPErrorHandler($errno, $errstr, $errfile, $errline) {
   throw new ErrorFromPHPException($errstr, $errno);
}
...
$oldhandler = set_error_handler('PHPErrorHandler');
fopen('/tmp/non-existent', 'r');
...
원상 복귀할 때도 set_error_handler를 사용하면 됩니다.
set_error_handler($oldhandler)
10. PHP에서 클래스를 생성하고 메소드를 호출할 때, 메소드가 없는 경우 __call()가 호출됩니다. (책에서는 오버로딩 시 사용합니다. 메소드 매개변수가 다른 경우 내부에서 __call()에서 적절한 메소드를 체크하여 호출시킵니다.)

11. __autoload() 정의되어 있지않은 클래스를 초기화하려는 경우 호출됩니다. (include되지 않은 클래스를 자동으로 호출하려고 하는 경우)


출처: Manning, PHP in Action(Objects, Design, Agility) 보면서 요약한 내용입니다.

2007년 7월 22일 일요일

document.write없이 html삽입하기

document.write을 사용해서 javascript코드를 삽입하는 방법은 다음의 문제를 가지고 있습니다.
  1. XHTML 모드에서 동작하지 않습니다.
  2. document.write를 써서 추가된 코드는 API를 사용하여 접근할 수 있는 방법이 없습니다.
  3. document.write는 HTML을 노드로 보지 않고 Serialized text로 보는 전혀 다른 관점을 지니고 있습니다.(DOM하고 비교했을 때)
document.write가 아닌 DOM을 이용해서 코드를 삽입하려면 다음의 방법을 선택할 수 있습니다.

  1. 호출할 javascript코드를 페이지에 삽입합니다.
    <scrip type="text/javascript" id="syndication" src="syndication.js"></script>

  2. syndication.js에 다음의 코드를 추가합니다.
    // 삽입할 태그를 DOM을 이용해서 생성합니다.
    var newContent = document.createElement('p');
    newContent.id = 'syndicated-content';
    newContent.appendChild(document.createTextNode('Here is some syndicated content.'));

    var source = document.getElementById('syndication');
    // script태그의 바로 앞쪽에 newContent를 삽입하게 합니다.
    source.parentNode.insertBefore(newContent, source);
2의 코드는 document.write('<p id="syndicated-content">Here is some syndicated content</p>');와 동일한 역할을 합니다.

출처: Insert in place without document.write via Simon Willison’s Weblog