본문 바로가기
PHP/생활코딩

5/30(3) 생활코딩

by SKim입니다 2020. 5. 30.

* 오늘의 진도

 PHP

  접근 제어자 (access modifier)

 

30. 접근 제어자 (access modifier)

encapsulation (캡슐화)

- 목표: 불필요한 정보를 감추는 것

 

객체 지향에서 encapsulation을 할 수 있도록 제공하는 기능

- 대표적인 것이 access modifier(접근 제어자)= property visibility이다.

  - 객체를 사용하는 입장에서 그 객체가 갖고 있는 인스턴스 변수/메소드에

    사용하는 쪽에서 접근할 수 있게 할 것이냐 없게 할 것이냐를 결정하는 기능

 

이전에 작성했던 코드이다.

객체의 내부는 클래스 안에 들어있고,

- 객체를 만드는 부분

- 객체 내부에 존재하는 인스턴스 변수나 메소드 등을

  외부에 노출시킬 것인지, 내부적으로만 사용할 것이지를 결정하는 것이

  access modifier(접근 제어자)= property visibility이다.

 

그 객체를 사용(조작)하는 입장은 아랫부분이다.

- isFile을 호출하고, filename을 읽어오고

 

 

우리가 작성한 코드는 생성자(__construct)를 통해서 정보를 주입하고 있다.

이렇게 할 수도 있지만 다른 방법으로 해보자.

 

주석처리를 하고

 

 

이렇게 해도 작동은 잘 된다.

= 우리가 객체가 있으면 인스턴스가 있으면

저 인스턴스의 내부적으로 사용할 filename이라는 변수에

직접 data.txt라는 파일을 넣고 있다.

 

이렇게 한다고 잘못한 것은 아닌데 단점이 있다.

 

만약에 이 객체를 만들고 있는 우리가

이 객체의 내부 '상태'인, 파일의 이름을 지정하는 시점에서

이 파일이 존재하는지 존재하지 않는지를 체크해서

존재하지 않는다면 이 프로그램을 그냥 종료시켜버려서

그 다음 명령을 아예 실행하지 못하게 하고 싶을 수도 있다.

 

그런 경우에 우리가 변수를 직접적으로 값을 세팅하면 그렇게 할 수 없다.

그런데 위에서 봤던 것처럼 생성자를 사용하면 그렇게 할 수 있다.

 

 

주석을 다시 살렸다.

 

어떻게 하냐면,

MyFileObject라는 클래스가 호출될 때, data.txt라는 값이 주입된다.

이 값이 주입된 이후/이전에

여기 3행에서 이 값에 해당되는 파일이 실제로 존재하는지 확인하고

없다면 프로그램을 종료시키는 코드를 만들 수도 있다.

 

 

파일이 존재하지 않을 경우,

if 뒤의 ( )가 false가 되어서 die(프로그램 종료)가 실행되면서 문구를 화면에 출력한다.

 

 

그래서 차이는?

 

1) 이전에는 인스턴스 변수에 직접 엑세스해서 파일의 이름을 직접 지정했다.

→ 단점: 인스턴스 변수가 세팅되는 순간에

 (들어오면 안 되는) 존재하지 않는 파일명이 들어왔을 때

 그것을 거절할 수 있는 방법이 없다.

 

 즉, 이 데이터가 오염되었는지 여부를 체크할 수 없다.

 (물론 파일의 이름이 없다고 오염된 것은 아니지만)

 

 

2) 하지만 생성자를 썼더니,

이렇게 들어온 데이터가

존재하는지 여부를 체크할 수 있는 기회를 가질 수 있다.

 

 

 

그렇게 해서 우리가 filename을 사용자가 직접 다루지 않고

 

생성자를 통해서 들어온 데이터가 결과적으로 파일의 이름이 되도록 프로그램을 바꿨다.

 

 

이 상태에서 사용자가 파일 이름을 없는 파일로 바꿔버리는 것이 코드상으로 가능하다.

why? 물론 생성자 차원에서 입력값을 받고 체크하는 것도 가능하지만

엄연히 이 객체는 내부적으로 filename이라는 인스턴스 변수를 쓰고 있고,

이 객체 외부에서 filename 값을 

 

이것을 통하지 않고 filename을 통해서 직접 파일의 이름을 세팅하는 것은 자기 마음인 것이다.

 

 

이런 것을 못하도록 하는 방법이 있다.

즉 filename의 값을 객체 외부에서는 세팅하지 못하도록 규제하는 방법이 있다.

= access modifier(접근 제어자)= property visibility

 

$filename 앞에 private라고 선언해주는 것이다.

 

 

위 그림처럼 객체가 생성된 후에 filename을 직접 지정하려고 하는 시도가 있을 때

어떻게 되는지 보자.

 

이 객체의 property, 인스턴스 변수인 filename에 직접적으로 접근하려고 했더니

php가 에러를 때려버리면서 중지시켜버린다.

 

∵ 해서는 안 되는, 내부에 존재하는 인스턴스 변수

 다른 말로는 property에 직접 접근하려고 했기 때문이다.

 

직접 접근하지 못하도록 강제하는 규제가 access modifier이고,

private로 되어 있는 변수는 외부에서 접근하려고 하면

프로그램이 딱 꺼져버린다.

 

 

반대로 private 말고 외부에서 직접 접근하는 것을 허용하고 싶다면

아무것도 안써도 되지만

public이라고 쓰면 허용하게 된다.

 

 

그런데 이렇게 private로 해놓으면

마지막 줄에서 인스턴스의 filename이라는 변수에 접근하려고 하면 에러가 난다.

 

∵ private로 지정되어 있는 변수를 읽으려고 했기 때문에

 

그럼 우리가 만약에 내부적으로 이 객체의 filename이 뭔지 알고싶으면

private로 하면 안 될까? 된다.

 

private으로 하고, 이 private한 property/변수를 리턴해주는 메소드를 정의하면 된다.

 

 

 

 

 

이번 시간에는 access modifier에 대해서 깔끔하게 정리해보자.

$name이라고 하는 변수를 직접 세팅하는 것을 막고 싶을 수 있다.

그런 경우에는 명시적으로

$name은 이 인스턴스 안에서 전역적으로 사용하는 변수라고 지정하고

앞에 private을 붙인다.

 

그럼 에러가 뜬다.

∵ name에는 직접적으로 접근하는 것이 금지되어 있기 때문

 

그럼 어떻게 하지?

2행을 주석처리하고 3행으로 바꿨다.

 

 

마지막 두 줄을 추가해줬다.

그러면 잘 동작한다.

 

setName으로 인해서

 

$this->name 값이 세팅된 것이다.

 

 

이 때 우리가 메소드를 통해서 private한 변수에 접근하는 것의 장점은

 

만약 $_name의 값이 없다면 문구를 출력하면서 die하도록 할 수 있다.

 

 

그러면 여기에 빈 공백을 주면 I need name이 뜬다.

 

 

∴ 이렇게 값의 유효성을 체크할 기회가 있다는 것이

 메소드를 통했을 때의 장점이다.

 

 

그리고 만약에 나중에 어떤 이유로 인해서

egoing이라는 변수의 name이 무엇인지 알고싶다면

마지막줄처럼 하면 에러가 뜬다.

$name은 private이기 때문이다.

 

이럴 때도 메소드를 통해서 접근하면 된다.

 

 

두 번째 function을 추가하고

 

원래 썼던 것을 주석처리하고 이렇게 쓰면

 

 

그래서 우리가 프로그래밍을 할 때,

어떤 특정한 변수를 외부로부터 은닉해야 될 때는

 

그 변수의 이름 앞에 set을 붙여서 ($name → setName)

값을 세팅하는 메소드를 제공하고,

 

 

이름 앞에 get을 붙여서 값을 가져오는 메소드를 제공해서

내부적으로 사용할 데이터를 외부로부터 감춰서 오염되는 것을 막을 수 있다.

 

이런식으로 코딩하는 관습을

set get 메소드라고 부른다.

 

set get 메소드로 하면 코드가 훨씬 더 복잡해지고

타이핑할 것도 많아지지만

장점도 분명히 있다.

 

 

그런데 직접적으로 변수에 접근하는 것이 잘못된 것이냐

그렇지 않다.

굳이 이럴 필요가 없으면 직접 접근하면 된다.

 

그런데 SW가 규모가 생김에 따라서 데이터를 강력하게 보호해야 되는 상황이 생기는데,

그런 상황에서는 set get 메소드를 쓰는 것이고,

 

에디터에 따라서 set get 메소드를 생성하는 것을 자동화해주는 툴도 있다.

 

ex) php 스톰 - 마우스 우클릭 - generate - Getters and Setters를 클릭하면

 이 Person이라는 클래스에 있는 property를 보여준다.

 name을 선택하고 ok를 누르면

위의 코드가 아래처럼 바뀐다.

 

 

 

지금까지는 데이터 은닉화에 대해서 알아봤다.

 

그런데 클래스를 만들고 객체를 만드는 과정에서

어떤 메소드는 그 메소드를 사용하는 쪽(아래 그림 선택부분)에서 사용하도록 해야 되는 것이 있고,

내부적으로만 사용하도록 해서,

외부에서는 사용을 못하도록 강제해야 되는 경우가 있다.

 

그래서 내부적으로 사용할 수 있는 함수를 한 번 만들어 보고,

그 함수는 외부에서 사용할 수 없도록 규제해보자.

 

위 그림에 선택한 부분은 메소드는 아니지만

서로 연관되어있는 코드들이다.

그럼 우리가 저것을 메소드화 시킬 수 있다.

= 메소드 추출 기법

= 로직을 메소드화시키는 것

 

로직이 길면 당연히 메소드화시켜야 하고

짧아도 메소드화시켰을 때의 장점이 현저히 크다.

 

선택한 부분은 하는 일이

데이터가 있는지 체크해서 없으면 죽는 것이다.

 

getName 함수 밑에

ifEmptyDie 함수를 만들어주었다.

 

setName 함수에 2행을 추가하고 선택한 부분을 지웠다.

 

함수화 하기 전의 로직은, 그것이 어떤 기능을 하는지 이해해야 하는데,

메소드 추출 기법을 사용하자 이름을 보면 뭔지 대충 감이 온다.

 

그런데 이 ifEmptyDie라는 함수는

지금 상태에서는 이 인스턴스 밖에서도 사용할 수 있는 상태이다.

 

그런데 과연 ifEmptyDie라는 메소드가

Person이라는 클래스를 사용하는 사람에게 필요한 기능일까?

아니다.

 

우리가 만약 이 객체를 사용하는 사용자에게

저 객체에서 필요한 핵심적인 기능만을 보이게 하고 싶다면

그렇지 않은 것을 감추는 기능이 필요하다.

 

ifEmptyDie를 감추고 싶으면 

앞에 private을 붙이면 된다.

 

 

그래서 우리가 메소드를 만들 때,

그 메소드에 접근제어자를 붙인다고 하는 것을 이런 관점으로 보면 좋다.

 

public이 붙어있는 메소드는

그 클래스를 사용하는 사용자가 그 클래스를 조작하는 조작장치로써 우리가 지정한 것이라고 볼 수 있다.

 

private이 붙어있는 메소드는

사용하지 못하도록 강제시킨, 

내부적으로 사용하는 메소드라고 선언한 것이다.

 

 

앞으로 메소드를 만들 때 기본적으로는 private로 만드는 것이 좋다.

그리고 나중에 그 객체를 사용하는 과정에서

그것을 외부에서 사용할 필요가 생기면

그 때 그것을 pubilc으로 바꾸면 된다.

 

우리가 pubilc으로 선언한 메소드는

이미 사용자들이 사용하고 있는 상태이기 때문에

메소드의 이름이나 형식을 바꿀 수 없다.

 

그러므로 최대한 보수적으로

기본은 다 private이고 필요할 때 숙고해서 public으로 만드는 것이

더 좋은 접근이라고 프로그래머들이 말한다.

'PHP > 생활코딩' 카테고리의 다른 글

5/31(3) 생활코딩  (0) 2020.05.31
5/31 생활코딩  (0) 2020.05.31
5/30(2) 생활코딩  (0) 2020.05.30
5/30 생활코딩  (0) 2020.05.30
5/29(7) 생활코딩  (0) 2020.05.30

댓글