PHP에서 객체를 생성할 때, =와 =&의 차이점에 대해서...

lsj0713의 이미지

php를 공부하던중 =와 =&에 대해서 이상한 차이점을 발견하여 글을 올리게 되었습니다.

<?php

$GLOBALS['TA'] = "";

class A
{
    var $str;
function A($str)
{
    $this->str = $str;
    $GLOBALS['TA'] =& $this;
}
};

// 복사에 의한 대입
$e = new A("E1");
var_dump($GLOBALS['TA']);
$e->str = "E2";
var_dump($GLOBALS['TA']);

// 참조에 의한 대입
$r =& new A("R1");
var_dump($GLOBALS['TA']);
$r->str = "R2";
var_dump($GLOBALS['TA']);

?>

== 결과 ==

$ php -f t2.php
object(a)(1) {
  ["str"]=>
  string(2) "E1"
}
object(a)(1) {
  ["str"]=>
  string(2) "E1"
}
object(a)(1) {
  ["str"]=>
  string(2) "R1"
}
object(a)(1) {
  ["str"]=>
  string(2) "R2"
}
$

전 지금까지는 두가지 다 동일한 코드라 생각했고, 보통 $n = new Class; 쪽을 선호해 왔는데(보통 =로 쓰라고 추천하더군요), 오늘 코딩하면서 이상하게 객체가 둘로 갈라지는 현상이 보여서 문제점을 찾다가 위와 같은 현상을 발견하게 되었습니다. 제가 의도한 동작은 생성자에서 전역변수 TA에 객체의 참조를 저장하는 것인데, = 로 대입하면 객체가 두개가 생성이 되어서 서로 연결이 되지 않더군요;;;

그렇다면, new로 새로운 객체를 만들때는 반드시 =&로 대입해 줘야 한다는 얘기가 됩니다. 만약 위의 경우처럼 생성자에서 전역변수에 자기자신을 등록한다던가 하는 일을 하게 되면 문제가 생길 수 있기 때문입니다.

다른 분들은 이 문제에 대해서 어떻게 생각하십니까? 위와 같이 new로 객체를 생성할 때 =를 써야 된다고 생각하십니까? 혹은 =&을? 제가 보기엔 =& 쪽이 일반적으로 C++에서 쓰이는 것과 같은 의미가 되므로 이쪽이 더 바람직한 것 같습니다만...

ps. 참고로, 제가 만들던 클래스는 다음과 같습니다. 생성자와 소멸자가 상속이 되도록(혹은 상속시에 좀 더 편하게 부모 클래스의 생성자와 소멸자를 호출할 수 있도록) 하고, 만약 프로그래머가 소멸자를 호출하지 않았을 경우에는 자동으로 소멸자를 선언된 순서의 역순으로 호출해 주도록 하는 기반 클래스 입니다. *.Test.php는 이 클래스의 테스트 프로그램으로, 소멸자가 2번(프로그래머에 의해서 1번, destroyObject() 함수에 의해서 1번) 호출되었을때의 동작을 보여주는 프로그램입니다.

BaseObject.php :

<?php

$GLOBALS['_transient']['DestructorList'] = array();

function registerDestructor($ref, $funcname)
{
    var_dump($ref);
    array_unshift(
        $GLOBALS['_transient']['DestructorList'],
        array(&$ref, $funcname)
    );
}

function destroyObject()
{
    foreach ($GLOBALS['_transient']['DestructorList'] as $obj)
    {
        if ( is_object($obj[0]) && method_exists($obj[0], $obj[1]) )
        {
            if ( !isset($obj[0]->isDestroyed) || !$obj[0]->isDestroyed )
            {
                $obj[0]->{$obj[1]}();
            }
        }
    }
}

register_shutdown_function('destroyObject');

////////////////////////////////////////////////////////////////////////////////

class BaseObject
{
    var $errNo;
    var $errMsg;
    var $isDestroyed;

function BaseObject()
{
    $args = func_get_args();
    call_user_func_array(array(&$this, "_constructor"), $args);
}

function _constructor($s = "Default")
{
    registerDestructor(&$this, "_destructor");

    $this->errNo = 0;
    $this->errMsg = "";
    $this->isDestroyed = false;
}

function _destructor()
{
    $this->isDestroyed = true;
    echo "[OK" . $this->isDestroyed . "]<br />\n";
}

function setErr($no, $msg)
{
    $this->errNo = $no;
    $this->errMsg = $msg;
}

};

?>

BaseObject.Test.php :

<?php

include_once("BaseObject.php");

class AA extends BaseObject
{
    var $str_;

function _constructor($a = "Default")
{
    parent::_constructor();
    $this->str_ = $a;
}

function _destructor()
{
    echo "Destructor AA($this->str_)<br />\n";
    parent::_destructor();
}

function p()
{
    echo "[" . $this->str_ . "]<br />\n";
}

};

////////////////////////////////////////////////////////////////////////////////

class AAA extends AA
{
function _constructor($a = "Default")
{
    parent::_constructor($a);
}

function _destructor()
{
    $this->isDestroyed = true;
    echo "Destructor AAA($this->str_)<br />\n";
    parent::_destructor();
}

};

////////////////////////////////////////////////////////////////////////////////


$c =& new AAA("3");
$c->_destructor();

echo "========<br />\n";

?>
ssehoony의 이미지

PHP 에서 $a =&$b 는 레퍼런스 입니다.
C++ 의 경우 int& a = b; 이런식인것 과 같죠

PHP의 $a = $b 는 복사입니다.
PHP 5 에서는 object 는 $a = $b 하면 기본적으로 레퍼런스가 될거라고 했는데 사용안해봐서 모르겠군요.

$a = new class; 를 C의 개념으로 생각하시는 것 같은데
이때는 new class 를 하면 임시 객체가 생기고 $a 에 복사를 하는 그런게
아닙니다. $a 가 바로 new class 가 되는거죠.

lsj0713의 이미지

devilhero wrote:

$a = new class; 를 C의 개념으로 생각하시는 것 같은데
이때는 new class 를 하면 임시 객체가 생기고 $a 에 복사를 하는 그런게
아닙니다. $a 가 바로 new class 가 되는거죠.

저도 그렇게 알고 있었고, 그래서 늘 $a = new class;의 형태로 써 왔는데 위의 예제에서는 다음과 같이 동작합니다.

$a = new Class;

1. 임시객체 생성
2. 생성자 함수 호출
3. 임시객체를 $a에 복사.

그렇지 않으면 위의 예제코드가 설명되지 않습니다. 물론 속도는 일반적인 상식과는 다르게 참조인 =&보다 = 쪽이 빠르다고 들었습니다.

소타의 이미지

저는 =&를 사용합니다. fastcgi모드로 돌려보면 메모리 사용량이 틀립니다. PHP는 클래스 뿐만 아니라 모든 변수의 참조 전달이 복사보다 느리다고 알려져 있는데 클래스가 커지면 참조가 훨씬 가벼워집니다.. 저는 대부분의 함수의 리턴도 참조로 전달받고 뭐.. 그렇습니다 =_=;
$a=&addslashes($b); 이런식으로요..

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.