Text/Compiled by Zhu Xianzhong
1. 소개
다행스럽게도 PHP 5.0에서는 객체 오버로딩 기술이 도입되었습니다. 이 기사에서는 __call(), __set() 및 __get() 메서드의 오버로드 가능성을 살펴보겠습니다. 오버로딩 이론에 대한 간략한 소개 후, 두 가지 예를 통해 주제로 바로 넘어갈 것입니다. 첫 번째 예는 영구 저장소 클래스를 구현하는 것입니다. 두 번째 예는 동적 getter/setter를 구현하는 방법을 찾는 것입니다.
2. 객체 오버로딩이란 무엇입니까?
PHP에서 객체 오버로딩에 관해 이야기할 때, 우리는 두 가지 유형을 구별해야 합니다:
·메서드 오버로딩
·속성 오버로딩
메소드 오버로딩의 경우, 정의되지 않은 메소드에 대한 일반 호출을 구현하는 매직 메소드 __call()을 정의해야 합니다. 해당 수업에서. 이 일반 메서드는 클래스에서 정의되지 않은 메서드에 액세스하려는 경우에만 호출됩니다. 메소드 오버로딩이 없으면 다음 예제는 PHP가 치명적인 오류 메시지를 표시하게 합니다: 9행에서/some/directory/example.php의 정의되지 않은 메소드 ThisWillFail::bar()를 호출하고 프로그램 실행을 중단합니다:
< ?php
클래스 ThisWillFail {
공개 함수 foo() {
"Hello World!"를 반환합니다.
}
}
$class = 새로운 ThisWillFail;
$클래스->바();
?>
메소드 오버로딩의 도움으로 코드는 이 호출을 포착하고 우아하게 처리할 수 있습니다.
속성 오버로딩은 메서드 오버로딩과 유사합니다. 이 경우 클래스는 읽기/쓰기 작업을 클래스에 명시적으로 정의되지 않은 클래스 속성으로 리디렉션(프록시라고도 함)합니다. 여기서 특수 메서드는 __set() 및 __get()입니다. 오류 보고 수준에 따라 PHP 변환기는 일반적으로 정의되지 않은 속성에 액세스할 때 알림을 발행하거나 변수를 연기하고 잠재적으로 정의합니다. 속성 오버로드를 사용하는 경우 변환기는 정의되지 않은 속성을 설정할 때 __set()를 호출하고, 정의되지 않은 속성 값에 액세스할 때 __get()을 호출할 수 있습니다.
정리하자면, PHP와 같은 동적 언어를 사용할 때 오버로딩 기술을 사용하면 소프트웨어 개발 시간을 크게 단축할 수 있습니다.
이때 이론을 소개하고 구체적인 코딩을 분석하면 다음과 같다.
3. 영구 저장소 클래스의 예
다음 코드는 속성 오버로딩 기술을 사용하여 50줄 미만의 PHP 코드로 위에서 언급한 영구 저장소 클래스를 구현합니다. 지속성이라는 용어는 클래스가 데이터 구조의 요소를 설명하고 기본 스토리지 시스템과 동기화를 유지할 수 있음을 의미합니다. 코딩 측면에서 외부 코드는 클래스를 사용하여 데이터베이스 테이블에서 행을 선택할 수 있습니다. 이런 방식으로 프로그램이 실행 중일 때 클래스의 속성에 직접 액세스하여 행의 요소를 조작(읽기/가져오기)할 수 있습니다. 스크립트가 끝나면 PHP는 업데이트된 행 데이터를 데이터베이스로 다시 보내는 작업을 담당합니다.
다음 코드를 주의 깊게 연구하면 속성 오버로딩이 무엇인지 이해하는 데 도움이 됩니다.
<?php
//PEAR의 <a href=" http://pear.php.net/package/DB/ "> DB 패키지</a> 로드
require_once "DB.php";
클래스 지속 가능 {
개인 $data = 배열();
개인 $table = "사용자";
공개 함수 __construct($user) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");
$query = "ID, 이름, 이메일, 국가를 선택하세요. FROM " .
$this->table . " 이름 = ?";
$this->data = $this->dbh->getRow($query, 배열($user),
DB_FETCHMODE_ASSOC);
}
공개 함수 __get($member) {
if (isset($this->data[$member])) {
$this->data[$member]를 반환합니다.
}
}
공개 함수 __set($member, $value) {
//데이터세트의 ID는 읽기 전용입니다. if ($member == "id") {
반품;
}
if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}
공개 함수 __destruct() {
$query = "업데이트" . $this->테이블 . " SET 이름 = ?,
이메일 = ?, 국가 = ? ID = ?";
$this->dbh->query($query, $this->이름, $this->이메일,
$this->국가, $this->id);
}
}
$class = new Persistable("마틴 얀센");
$class->name = "존 도우";
$class->country = "미국";
$class->email = " [email protected] ";
?>
직면할 수 있는 첫 번째 문제는 PHP 5에 도입된 새로운 생성자 메서드인 __construct()입니다. PHP 4 시대에는 생성자가 항상 클래스 이름과 일치했습니다. PHP 5에서는 더 이상 그렇지 않습니다. 생성자 메서드를 호출하면 클래스의 인스턴스가 생성되고 여기서 매개변수가 사용된다는 점을 제외하면 생성자 메서드에 대해 많이 알 필요가 없습니다. 데이터베이스는 이 매개변수를 기반으로 실행됩니다. 이 생성자는 쿼리 결과를 클래스 속성 $data에 할당합니다.
다음으로 프로그램은 __get() 및 __set()라는 두 가지 특수 메서드를 정의합니다. 이미 익숙할 것입니다. __get()은 정의되지 않은 속성 값을 읽는 데 사용되고 __set()은 정의되지 않은 속성 값을 수정하는 데 사용됩니다.
이는 정의되지 않은 속성이 영구 저장소 클래스에서 읽혀지거나 쓰여질 때마다 이러한 특수 메서드가 클래스의 속성을 직접 변경하는 대신 속성 배열 변수 $data의 정보를 관리하는 일을 담당한다는 것을 의미합니다. 데이터베이스의 행을 포함합니다!).
클래스의 마지막 메소드는 __construct()의 반대인 소멸자 __destruct()입니다. PHP는 일반적으로 PHP 스크립트 실행이 거의 끝나가는 "스크립트 종료 단계" 중에 소멸자를 호출합니다. 소멸자는 $data 속성의 정보를 데이터베이스에 다시 씁니다. 이것이 바로 이전 용어 동기화의 의미입니다.
여기 코드가 PEAR의 데이터베이스 추상화 계층 패키지를 사용한다는 것을 눈치챘을 것입니다. 사실, 다른 방법을 통해 데이터베이스와 통신하는 것도 이 기사의 주제를 설명할 수 있습니다.
주의 깊게 살펴보면 이 영구 저장소 클래스에 대한 설명이 비교적 간단하다는 것을 알 수 있습니다. 이 예에는 데이터베이스 테이블만 포함되어 있으며 LEFT JOIN 사용 및 기타 복잡한 데이터베이스 운영 기술과 같은 더 복잡한 데이터 모델은 고려하지 않습니다. 그러나 이에 얽매일 필요는 없으며 속성 오버로딩의 도움으로 자신만의 이상적인 데이터베이스 모델을 사용할 수 있습니다. 약간의 코드만으로 이 영구 스토리지 클래스의 복잡한 데이터베이스 기능을 활용할 수 있습니다.
또한 작은 문제가 있습니다. 소멸자에서 쿼리가 실패할 때 오류 처리 메커니즘이 도입되지 않습니다. 이 경우 적절한 오류 메시지를 표시하는 것이 불가능하게 만드는 것은 소멸자의 특성입니다. PHP가 소멸자를 호출하기 전에 HTML 마크업 빌드가 종료되는 경우가 많기 때문입니다.
이 문제를 해결하려면 __destruct()의 이름을 saveData()와 같은 이름으로 바꾸고 호출 스크립트의 어딘가에서 이 메서드를 수동으로 실행할 수 있습니다. 이는 클래스에 대한 영구 저장소의 개념을 변경하지 않으며 단지 몇 줄의 코드만 추가하면 됩니다. 또는 소멸자의 error_log() 함수를 사용하여 시스템 전체 오류 로그 파일에 오류 메시지를 기록할 수 있습니다.
이것이 속성 오버로딩이 작동하는 방식입니다. 다음으로 메소드 오버로딩에 대해 논의합니다.
4. 메소드 오버로딩의 예
1. 동적 Getter/Setter 메소드
다음 코드는 메소드 오버로딩의 도움으로 클래스를 제어하기 위해 "동적" getter/setter 메소드를 구현합니다. 소스 코드를 기반으로 분석해 보겠습니다.
<?php
클래스 DynamicGetterSetter {
private $name = "마틴 얀센";
private $starbucksdrink = "카라멜 카푸치노 소용돌이";
함수 __call($method, $arguments) {
$prefix = strtolower(substr($method, 0, 3));
$property = strtolower(substr($method, 3));
if (빈($prefix) || 비어 있음($property)) {
반품;
}
if ($prefix == "get" && isset($this->$property)) {
$this->$property를 반환합니다.
}
if ($prefix == "설정") {
$this->$property = $인수[0];
}
}
}
$class = 새로운 DynamicGetterSetter;
echo "이름: " . $class->getName() .
echo "가장 좋아하는 스타벅스 맛: " . $class->getStarbucksDrink() "nn";
$class->setName("John Doe");
$class->setStarbucksDrink("클래식 커피");
echo "이름: " . $class->getName() .
echo "가장 좋아하는 스타벅스 맛: " . $class->getStarbucksDrink() "nn";
?>
분명히 여기서 $name 및 $starbucksdrink 두 속성은 비공개이므로 클래스 외부에서는 이러한 속성에 액세스할 수 없습니다. 객체 지향 프로그래밍에서는 비공개 속성의 값에 액세스하거나 수정하기 위해 공개 getter/setter 메서드를 구현하는 것이 매우 일반적입니다. 이를 구현하는 것은 지루하고 시간과 노력이 많이 소요됩니다.
이 문제는 메소드 오버로딩을 통해 쉽게 해결할 수 있습니다. 위의 경우 각 속성에 대해 getter/setter 메서드를 구현하는 대신 일반적인 __call() 메서드만 구현합니다. 이는 setName() 또는 getStarbucksdrink()와 같은 정의되지 않은 getter/setter 메서드가 호출될 때 PHP가 치명적인 오류를 생성하지 않고 중단하는 대신 마법의 __call() 메서드를 실행(또는 위임)한다는 의미입니다.
이것은 몇 가지 간단한 소개입니다. __call()에 대한 심층 분석을 해보겠습니다.
2. __call() 메서드에 대한 자세한 분석
__call()의 첫 번째 매개 변수는 원래의 미확인 메서드(예: setName)입니다. 두 번째 매개 변수는 모든 원래 메서드를 포함하는 숫자 인덱스가 있는 1차원 배열입니다. . 두 개의 매개변수("Martin" 및 42)를 사용하여 정의되지 않은 메소드를 호출하면 다음 배열이 생성됩니다.
$class->thisMethodDoesNotExist("Martin", 42);
/__call()의 두 번째 매개변수에 대한 안내
정렬
(
[0] =>마틴
[1] => 42
)
__call() 메서드 내에서 원래 메서드가 get 또는 set으로 시작하는 경우 코드가 getter/setter 메서드를 호출하는지 확인하기 위해 일부 계산을 수행해야 합니다. 게다가 이 메소드는 메소드 이름의 또 다른 구성요소(처음 세 문자 제외)를 추가로 분석합니다. 왜냐하면 문자열의 뒷부분은 getter/setter가 참조하는 속성의 이름을 나타내기 때문입니다.
메서드 이름이 getter/setter를 나타내는 경우 메서드는 해당 속성 값을 반환하거나 원래 메서드의 첫 번째 매개 변수 값을 설정합니다. 그렇지 않은 경우 아무 작업도 수행하지 않고 아무 일도 일어나지 않은 것처럼 프로그램을 계속 실행합니다.
3. 목표를 달성하려면
본질적으로 모든 속성에 대응하여 코드가 모든 getter/setter 메서드를 동적으로 호출할 수 있도록 하는 메서드가 있습니다. 이 알고리즘이 존재합니다. 이는 단기적으로 프로그램 프로토타입을 개발할 때 편리합니다. getter/setter를 구현하는 데 많은 시간을 소비하는 대신 개발자는 API 모델링과 애플리케이션이 근본적으로 올바른지 확인하는 데 집중할 수 있습니다. __call() 메서드를 추상 클래스에 통합하면 향후 PHP 프로젝트 개발에서 코드를 재사용할 수도 있습니다.
4. 단점 외에도
장점과 단점이 있습니다. 위 접근 방식에는 몇 가지 단점이 있습니다. 대규모 프로젝트에서는 phpDocumentor와 같은 도구를 사용하여 API 구조를 추적할 수 있습니다. 위에서 소개한 동적 메서드를 사용하면 물론 모든 getter/setter 메서드가 자동으로 생성된 문서에 나타나지 않으므로 추가 설명이 필요하지 않습니다.
또 다른 단점은 클래스 외부의 코드가 클래스 내의 모든 전용 속성에 액세스할 수 있다는 것입니다. 실제 getter/setter 메서드를 사용할 때 외부 코드에서 액세스할 수 있는 전용 속성과 클래스 외부에서 볼 수 없는 "실제" 전용 속성을 구별할 수 있습니다. 메서드 오버로딩이 있고 가상 getter 및 setter가 있기 때문입니다. 방법을 사용할 수 있습니다.
5. 결론
이 기사에서는 PHP 5.0에서 객체 오버로딩이 발생하는 두 가지 상황을 두 가지 예를 통해 주의 깊게 분석합니다. 이 기사의 방법이 PHP 프로그래밍의 효율성을 향상시키는 데 도움이 되기를 바랍니다. 동시에 이 방법의 단점도 분명히 볼 수 있습니다.