PHP 헤깔렸던 내용 정리
OOP(Object-Oriented Programming) 객체 지향 프로그램
절차 중심에서 효율화를 위해 객체 중심으로 프로그램의 흐름이 바뀌며 PHP에서 사용되는 프로그래밍 방법. 특정한 기능과 상수 등을 묶어둔 객체를 만들어 관리를 하게 되었는데 그게 CLASS 이다.
개발 중 공통적으로 사용하는 코드가 많이 발생하는데, 이러한 코드들의 재사용 하기 위해 객체 지향적인 프로그래밍을 지양하게 됨. PHP는 CLASS를 사용하지 않아도 객체 선언이나 사용은 가능하지만 그렇게 사용했을 시 굉장히 비효율적이다. 그 때 CLASS 키워드를 선언해 객체를 설계하고 함수, 상수 등... 재사용 할 수 있는 코드들을 정리해 더욱 코드의 효율을 높일 수 있다. 그래서 CLASS를 선언해 객체를 설계하고 사용한다.
반복적으로 사용될 변수, 상수, 함수등을 정의하고 모아둔것.
장점
1) 중복되는 코드들을 제거하고 가독성을 높힌다.
2) 모듈화, 재사용을 할 수 있게 만들어 코드의 코드를 줄인다.
3) 수정이 일어날 범위를 class내부로 좁혀 유지 보수를 편하게 한다.
<?php
class Car_Engine {
// 프로퍼티(멤버 변수)
private $_displacement;
public $engineName;
// 메소드
public function getDisplacement() {
return $this->_displacement;
}
public function setDisplacement($displacement) {
$this->_displacement = $displacement;
}
}
?>
1) 기본 구조
2) 이름규칙
<?php
class MyFileObject{
function isFile(){
return is_file('data.txt');
}
}
$file = new MyFileObject();
var_dump($file->isFile());
$file2 = new MyFileObject();
var_dump($file2->isFile());
?>
CLASS는 외부에서 new를 사용해 인스턴스를 생성하여 객체 선언이 필요하다.
클래스를 하나의 공간이라 치고 인스턴스를 그 공간에서 이루어질 무엇인가를 실체화 하는 것이라고 생각하자. 예를들어 추운겨울 맛있는 붕어빵이 있다. class는 천철역이라는 큰 도화지, 표현하자면 추운 겨울 전철역 앞 포장마차 같이 붕어빵이 만들어질 수 있는 어디어디를 표현하는 추상적인 개념공간 같은 것이라고 생각한다. 물론 전철역에서 할수 있는것이 너무 많이 너무 큰 네이밍이지 않나 싶긴하다. 예시니까 그냥 생각하자.
그리고 우리는 전철역이라고 썼듯이 function을 사용해서 붕어빵을 만들어 내는 행동을 할 수 있다. 그리고 인스턴스는 추상적으로 모아둔 모음집에서 실체화 할수 있도록 선언하는것이다. new 를 붙여서. new 황금잉어빵();
<?php
$doMakeFood = new TrainStation(); // 헤이 전철역 전철역에서 먹을걸 만들어야지.
(전철역에 있는 만들수 있는거 불러와)
$doMakeFood->GoldenCarpBread("슈크림"); //전철역 황금잉어빵! 그런데 난 슈크림맛!
class TrainStation{
public $staName = '판교'; //판교역에 있는걸 먹을거야.
public function GoldenCarpBread($contents) {
echo $this->staName."지점". $contents."잉어빵"; // 판교 지점 슈크림잉어빵
}
}
?>
1) public : 외부에서 CLASS 내부로 접근 가능
2) protected : 같은 클래스 및 자식 클래스에서 접근이 가능
3) private : 같은 클래스 내부에서만 사용 및 접근 가능. 파일이름 같은 것을 덮어쓸 수 없도록!
set, get 메소드를 만들어 사용함.
<?php
class Study {
//멤버변수의 선언
var $var0 = 0; //public으로 선언한 것과 동일, 사용하지 않음
public $var1 = 0; //접근제한 없음
protected $var2 = 0; //클래스 자신과 클래스를 상속한(서브클래스)에서만 접근
private $var3 = 0; //클래스 자신에서만 접근
const VALUE = 0; //상수 선언, 선언시 초기화된 값을 바꿀 수 없음
//메소드의 선언,
public function method1() {
/* running code */
}
protected function method2() {
/* running code */
}
private function method3() {
/* running code */
}
static function method4() {
/* running code */
}
}
?>
<?php
$object = new Study; //객체를 생성
$data1 = $object -> var1; //객체의 멤버변수에 접근하여 멤버변수의 값을 변수에 대입
$run1 = $object -> method1(); //객체의 메소드에 접근(호출)하여 반환된 값을 변수에 대입
$run2 = Study::method2(); //static으로 선언된 메소드는 ::로 호출, 객체가 아닌 클래스로 부터 호출
class Study {
public $var1 = 0;
const VALUE = 0;
public function method1() {
self::VALUE; //상수로 선언된 멤버변수는 ::로 접근 (Study의 VALUE)
/* running code */
}
static function method2() {
/* running code */
}
}
?>
$object1 = new ClassName; //객체를 생성
$object2 = $object1; //생성된 객체의 참조주소를 대입, $object1과 $object2는 동일한 객체에 접근함
$object3 = clone $object1; //생성된 객체를 복제하여 대입, $object1과 $object3은 각각 다른 객체를 참조함
지시자란 클래스 선언 시 내부의 변수, 함수에 접근할 수 있게 하는 명령어이다.
javascript에서 document.getElementById('아이디'); 를 예로 들어 ' . ' 처럼 php에서는 ->를 사용해 지시를 내린다. 객체를 생성하고 내부 변수 및 함수에 접근할 때 사용하면 된다.
객체 안에서 작업할 때 자신을 참조할 경우 사용하는 예약된 변수.
객체 내의 속성이나 메소드를 가리킬 때 사용. $표시는 this앞에만 붙여야 한다.
Class 내에서 다른 메소드(함수)에 접근할 때에는 $this 를 사용
$this->val 는 해당 클래스의 $val 변수에 접근한다는 것을 의미
$this는 현재 인스턴스를 가리키고 self는 명령이 실행되는 위치의 클래스 자체를 가리킴.
<?php
class Greeter{
function greet(){
echo 'hello';
}
function __construct(){
$this->greet(); //hello
self::greet(); //hello
}
}
?>
<?php
class X{
function greet(){ echo 'Greeting from X' }
function __construct(){
$this->greet(); // $obj->greet();
echo ',';
self::greet(); // X::greet();
}
}
class Y extends X{
function greet() { echo 'Greetings from Y'; }
}
$obj = new Y();
?>
결과: Greefing From Y, Greeting FROM X
obj)를 가키고 self는 명령이 실행되는 위치 __construct의 클래스 자체 X를 가리킴. self는 현재 클래스를 가리켜야 하는 경우 static등에는 self를 사용
스코프 해결 연산자(Paamayim Kekudotyim). 범위연산자라고도 하며 static이나 constant와 클래스의 재정의된 프로퍼티나 메서드에 접근할 수 있도록 해주는 토큰. 쉽게 생각하면 :: ~안에 라는 의미 같다.
변수의 값은 키워드여서는 안된다. (ex self, parent 과 static)
CLASS명 :: 클래스 상수 형식으로 사용
parent::__construct 부모 클래스에 있는 생성자 호출
self::function이름 자기 클래스 안 함수 호출
<?php
#예제1 클래스 정의 외부에서 ::
class MyClass {
const CONST_VALUE = 'A constant value';
}
$classname = 'MyClass';
echo $classname::CONST_VALUE; // As of PHP 5.3.0
echo MyClass::CONST_VALUE;
?>
<?php
#예제1 클래스 정의 외부에서 ::
class MyClass {
const CONST_VALUE = 'A constant value';
}
$classname = 'MyClass';
echo $classname::CONST_VALUE; // As of PHP 5.3.0
echo MyClass::CONST_VALUE;
?>
오버라이드는(Override) 부모클래스의 메소드를 재정의 하는 것. 재정의 시에는 메소드명과 인자가 동일해야 한다. 오버라이딩 규칙은 생성자에도 동일하게 적용.
메소드명이 같은데 인자가 다르면 에러가 발생합니다. 다른 객체 지향 언어는 메소드 오버로딩(overloading) 이라고 해서 메소드의 이름은 같고, 인자가 다른 메소드를 정의하여 주어지는 인자에 따라 다른 메소드가 호출되도록 할 수 있지만, PHP 는 오버로딩은 지원하지 않는다.
<?php
#예제3 부모 메서드 호출하기
// 부모메서드를 재정의하여 확장할때 php는 부모의 메서드를 호출하지 않음.
class MyClass
{
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}
class OtherClass extends MyClass
{
// Override parent's definition
public function myFunc()
{
// But still call the parent function
parent::myFunc();
echo "OtherClass::myFunc()\n";
}
}
$class = new OtherClass();
$class->myFunc();
?>
<?php
//간단 예시
class GoodBye {
const MESSAGE = '안녕 잘가.';
}
echo GoodBye::MESSAGE;
?>
__constructor : 생성자, 인스턴스를 생성할 때 해야 할 작업을 담아두는 메소드. 인스턴스가 생성됐을 때의 해야되는 필수적인 것을 함수에 적으면 초기화 작업을 할 수 있다. 인스턴스를 초기화 작업 할 때 사용하기도 한다.
__destruct : 인스턴스의 소멸되기 시점에 자동 호출. 이미 생성된 인스턴스를 더이상 참조하지 않을 때 해당 인스턴스 소멸 전 호출.
<?php
class Box {
public $name;
public $size;
function __construct($name, $size){ //생성자. 값 세팅
$this->name = $name;
$this->size = $size;
}
function __destruct(){
echo "박스이름은 {$this->name}이고, 사이즈는 {$this->size}입니다.";
}
}
$myBox = new Box("나의 박스", "최고 작은 사이즈");
?>
extends를 사용해 객체 간의 부모 자식 관계를 가지도록 하여 중복된 코드를 제거할 수 있고, 재사용 및 가독성을 높일 수 있다. 거꾸로 Box클래스에서 WantBox 함수는 사용할 수 없으니 주의객체 간의 부모 자식 관계를 가지도록 하여 중복된 코드를 제거할 수 있고, 재사용 및 가독성을 높일 수 있다. 거꾸로 Box클래스에서 WantBox 함수는 사용할 수 없으니 주의
<?php
class Box {
public $name;
public $size;
function __construct($name, $size){ //생성자. 값 세팅
$this->name = $name;
$this->size = $size;
}
public function intro(){
echo "필요한 것은 {$this->name} 이고 사이즈는 {$this->size} 입니다."
}
}
class WantBox extends Box {
public function message() {
echo "무슨 박스가 필요하나요?";
}
}
$myBox = new WantBox("나의 박스", "최고 작은 사이즈");
$myBox->message();
$myBox->intro();
?>
CLASS를 상속받을 때 하나의 클래스에서 하나의 부모 클래스만 상속이 가능하다. 다중으로 CLASS 사용하기 위해서는 trait선언하는 변수나 함수는 클래스와 같고 CLASS 키워드 자리에 trait로 선언하고 사용하고 클래스에서는 use를 사용해야 한다.
만일, trait를 사용할 때 같은 이름의 함수를 사용했을 경우, nsteadof를 사용해 어떤 트레이트에 포함된 함수를 가져다 사용할지에 대해 정의를 해줘야 한다.
trait.php
<?php
//첫번째 trait를 선언
trait testTrait1 {
public function pr_trait1(){
print_r( "첫번째 트레이트입니다." );
}
}
//두번째 trait를 선언
trait testTrait2 {
public function pr_trait2() {
print_r( "두번째 트레이트입니다." );
}
}
?>
main.php
//trait.php 파일 읽기
require_once ( "trait.php" );
class TestTrait {
//trait.php에 있는 트레이트를 사용선언
use testTrait1;
use testTrait2;
//숫자를 더하는 return 함수
public function pr_meclass( $plusNum ) {
$sumNum = $plusNum +100;
return $sumNum ;
}
}
//클래스로 인스턴스 생성
$test = new TestTrait();
//첫번째 트레이트에 있는 pr_trait1함수 호출
$test -> pr_trait1();
print_r( "<br><br>" );
//두번째 트레이트에 있는 pr_trait2함수 호출
$test -> pr_trait2();
print_r( "<br><br>" );
//클레스에 있는 pr_class 함수 호출하고 return 받음
print_r( $test -> pr_meclass(100));
결과
첫번째 트레이트 입니다.
두번째 트레이트 입니다.
200
<?php
trait message1{
public function msg1 (){
echo "첫번째 입니다.";
}
}
trait message2{
public function msg2(){
echo "두번째 입니다.";
}
}
class ShowMassage {
use message1, message2;
}
$obj = new ShowMassage();
$obj->msg1();
echo "<br/>";
$obj->msg2();
?>
결과
첫번째 입니다.
두번째 입니다.
함수가 작동을 끝내면 함수 내의 로컬 변수는 자동적으로 메모리에서 사라지는데, 이를 자동적으로 사라지지 않게 끔 할 수 있다. 이 키워드가 static이다. static멤버에는 변수와 메소드가 존재한다.
예를 들어, new로 인스턴스를 생성하면
정적 변수 = class::변수명
정적 메소드 = class::메소드명()
정적 메소드는 객체가 아닌 클래스로부터 호출되는 메소드.
클래스에 소속된 값이라 봐도 될 것 같다.
class A {
static function print_hello() {
echo "Hello World!";
}
}
A::print_hello(); // A클래스의 static형 print_hello(), Hello World! 출력
//정적 멤버 함수의 경우 instance가 생성되기 전에 사용이 가능하므로,
// $this->를 사용할 수가 없지만, 정적멤버 변수는 사용 가능하다.
class Person{
private static $count = 0;
private $name;
function __construct($name){
$this->name = $name;
self::$count = self::$count + 1;
}
function enter(){
echo "<h1>Enter ".$this->name." ".self::$count."th</h1>";
}
static function getCount(){
return self::$count;
}
}
$p1 = new Person('egoing');
$p1->enter();
$p2 = new Person('leezche');
$p2->enter();
$p3 = new Person('duru');
$p3->enter();
$p4 = new Person('taiho');
$p4->enter();
echo Person::getCount();
PHP의 모든 함수와 클래스는 전역이다.
함수가 내부에서 정의되었더라도 외부에서 호출할 수 있으며, 반대도 성립한다.
PHP는 함수 오버로딩(overloading)을 지원하지 않으며, 함수 정의를 해제하거나 이미 선언된 함수를 다시 선언할 수 없다.
*오버로딩 : 하나의 이름의 함수에 여러 기능 정의