php7.3 → php 8.1 migration

김포크레인·2022년 8월 8일
0
  • 관련 내용은 앞으로 확인 되는 대로 추가될 예정

클래스 상속 시, 메서드 내부 static 변수의 공유

  • 기존 7.3 에서는 클래스 상속 시, 메서드 내부의 static 변수들을 자식객체, 부모객체 서로 공유하지 않았으나, 8.1 부터는 공유하도록 변경되었다.
<?php
 
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
class A // 부모 클래스
{
    public static $val = 1; // static 변수는 원래도 공유되었음
    public static $arr = array() ; // static 변수는 원래도 공유되었음
     
    public function staticVarTestA($addVal = 0)
    {
        static $local = 1;     
        $local += $addVal;
        echo "[staticVarTestA] local: {$local}".PHP_EOL;
    }
 
    public static function staticVarTestB($addVal = 0)
    {
        static $local = 1;     
        $local += $addVal;
        echo "[staticVarTestB] local: {$local}".PHP_EOL;
    }
 
}
 
class B extends A
{
}
 
class C extends A
{
}
 
$A = new A(); // 부모객체
$B = new B(); // 자식객체 B
$C = new C(); // 자식객체 C
 
$A->staticVarTestA(1);   // 7.3 [staticVarTestA] local : 2       8.1 [staticVarTestA] local : 2
$B->staticVarTestA(10);     // 7.3 [staticVarTestA] local : 11     8.1 [staticVarTestA] local : 12
$C->staticVarTestA(100);    // 7.3 [staticVarTestA] local : 101        8.1 [staticVarTestA] local : 112
 
A::staticVarTestB(1);       // 7.3 [staticVarTestB] local : 2       8.1 [staticVarTestB] local : 2
B::staticVarTestB(10);      // 7.3 [staticVarTestB] local : 11      8.1 [staticVarTestB] local : 12
C::staticVarTestB(100);     // 7.3 [staticVarTestB] local : 101     8.1 [staticVarTestB] local : 112

stdClass 객체의 변수명에 { } 로 가변 변수명을 사용하는 것

  • 8.1 에서는 오류로 처리되는 코드
// 오류 테스트코드
<?php
 
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
$std = new stdClass();
for ($i = 0; $i < 3; $i++)
{
    $std->reward_{$i} = $i;
}
 
echo json_encode($std);
 
 
// 8.1 : Fatal error: Array and string offset access syntax with curly braces is no longer supported in /var/www/html/a_test/scribeTest.php on line 8
// 7.3 : {"reward_":[0,1,2]} // 만약 기대한 것이 {"reward_0":0, "reward_1":1, "reward_2":2 } 였다면, 기존에도 기대처럼 동작하지 않았다.
// 대체코드
<?php
 
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
// 방법 1
$std = new stdClass();
for ($i = 0; $i < 3; $i++)
{
    $col_name = "reward_{$i}";
    $std->$col_name = $i;
}
 
echo json_encode($std).PHP_EOL; // 7.3, 8.1 : {"reward_0":0, "reward_1":1, "reward_2":2 }
 
// 방법 2
for ($i = 0; $i < 3; $i++)
{
    $std->{"reward_{$i}"} = $i;
}
 
echo json_encode($std).PHP_EOL;  // 7.3, 8.1 : {"reward_0":0, "reward_1":1, "reward_2":2 }

php 내부 클래스/인터페이스의 상속/구현시 리턴타입 명시

  • 8.x 버전에서는 PHP 내부 클래스/인터페이스를 확장/구현하지만 리턴 타입을 추가하지 않은 많은 PHP 응용 프로그램에서 이 사용 중단 알림이 표시될 수 있다.
  • #[ReturnTypeWillChange] attribute를 추가하여 사용중단 알림을 회피할 수 있다.
  • 그러나 이 해결 방법은 PHP 9.0 이상에서는 작동하지 않으므로 일치하는 리턴 타입 선언을 추가해야 함.
  • GeoIP2.phar 를 사용하고 있었는데, 여기도 그 문제가 있어서 최신버전을 다운받아 해결함. GeoIP2.phar 2.13.0
  • 관련 문서
    - https://php.watch/versions/8.1/internal-method-return-types
    - https://php.watch/versions/8.1/ReturnTypeWillChange
/** 이슈코드
 * Objects implementing JsonSerializable
 * can customize their JSON representation when encoded with
 * <b>json_encode</b>.
 * @link https://php.net/manual/en/class.jsonserializable.php
 * @since 5.4
 */
interface JsonSerializable
{
    /**
     * Specify data which should be serialized to JSON
     * @link https://php.net/manual/en/jsonserializable.jsonserialize.php
     * @return mixed data which can be serialized by <b>json_encode</b>,
     * which is a value of any type other than a resource.
     * @since 5.4
     */
    #[TentativeType]
    public function jsonSerialize(): mixed; //---------------------> jsonSerialize 함수는 return 타입이 mixed로 정의되어있음
}
 
// 문제의 코드-------------------
class A implements jsonSerializable
{
    public $single;
    public $option;
 
    public function __construct()
    {
        $this->option = new option();
        $this->single = new single();
    }
 
    public function jsonSerialize() //----------------------------> jsonSerailizable을 구현하였으나 리턴타입을 작성하지 않음
    {
        $reflect = new ReflectionClass(__CLASS__);
        $a_properties = $reflect->getProperties();
 
        foreach ($a_properties as $property) {
            $name = $property->name;
            if ($this->$name == null) {
                unset($this->$name);
            }
        }
        return get_object_vars($this);
    }
}
 
// <b>Deprecated</b>:  Return type of A::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in <b>/var/www/html/test/A.php</b> on line 121
// 해결방법1 : interface의 return 타입을 일치하도록 맞춰준다.(9.0 에서도 안전한방법)
class A implements jsonSerializable
{
    public $single;
    public $option;
 
    public function __construct()
    {
        $this->option = new option();
        $this->single = new single();
    }
 
    public function jsonSerialize() : mixed //----------------------> 인터페이스에 정의된 return 타입과 일치하게 return 타입을 작성해준다.
    {
        $reflect = new ReflectionClass(__CLASS__);
        $a_properties = $reflect->getProperties();
 
        foreach ($a_properties as $property) {
            $name = $property->name;
            if ($this->$name == null) {
                unset($this->$name);
            }
        }
        return get_object_vars($this);
    }
}
 
// 해결방법2 : #[ReturnTypeWillChange] attribute를 추가한다. (5.x 버전에서는 return 타입이 없기 때문에 1의 방법으로 수정할 수 없으므로 임시조치하는 법. 단 9.0 에서는 동작하지 않음)
class A implements jsonSerializable
{
    public $single;
    public $option;
 
    public function __construct()
    {
        $this->option = new option();
        $this->single = new single();
    }
 
    #[ReturnTypeWillChange]
    public function jsonSerialize()
    {
        $reflect = new ReflectionClass(__CLASS__);
        $a_properties = $reflect->getProperties();
 
        foreach ($a_properties as $property) {
            $name = $property->name;
            if ($this->$name == null) {
                unset($this->$name);
            }
        }
        return get_object_vars($this);
    }
}

strlen() 의 parameter 로 null 이 들어올 때의 처리

  • 7.3 버전에서는 0을 반환하고, 8.1 에서는 deprecated 경고가 뜬다.
<?php
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
if (strlen(null) === 0)
{
    echo "true";
}
else
{
    echo "false";
}
 
// 7.3 의 결과 : true
// 8.1 의 결과 : Deprecated:  strlen(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/test.php on line 4

APC -> APCu 로 교체

  • APC (opcode cache + user cache) 에서 php 5.5 이상에서 opcache 기능을 공식 지원하면서 , APC의 user cache 부분만 떼어내서 만들어진 것이 APCu
  • 8.x 버전에서는 더이상 구버전의 APC를 지원해주는 모듈을 찾지 못해서, APCu 로 변경한다.
    • 만약 모듈이 있다면, 기존 걸 써도되는데, docker 관련해서 8.1을 지원하는 모듈을 찾지 못했음.
  • 각 함수에서 apc 부분을 apcu 로 교체하면 된다 (ex. apc_fetch → apcu_fetch)
  • apc로 저장한 걸 apcu 로 읽어올 수 있고, apcu로 저장한 걸 apc로 읽어올 수 있다. (즉 7.x 버전에는 일부 덜 고쳐진것이 있더라도 동작한다. 단, 8.1을 위해서는 모두 apcu로 고쳐져야한다.)
<?php
// APC 테스트
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
$key = phpversion()."hello!";
 
apc_store($key, $key);
 
echo phpversion()."결과:";
echo apc_fetch($key).PHP_EOL;
    // 7.3.27결과:7.3.27hello!
    // 8.1 : Fatal error:  Uncaught Error: Call to undefined function apc_store() in /var/www/html/a_test/testest.php:10
 
apc_delete($key);
 
echo phpversion()."결과:";
echo apc_fetch($key).PHP_EOL;
    // 7.3.27결과:
<?php
// APC <-> APCu 테스트 
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
$key = phpversion()."hello!?";
 
apc_store($key, $key);
 
echo "apc_store->apcu_fetch 결과:";
echo apcu_fetch($key).PHP_EOL;
 
apcu_store($key, $key."2");
//
echo "apcu_store->apc_fetch 결과:";
echo apc_fetch($key).PHP_EOL;
 
// -- 결과 (7.3 에서만 동작)--
// 7.3.27
// apc_store->apcu_fetch 결과:7.3.27hello!?
// apcu_store->apc_fetch 결과:7.3.27hello!?2
<?php

// APCu 테스트 
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
$key = phpversion()."hello";
 
apcu_store($key, $key);
 
echo "apcu_store->apcu_fetch 결과:";
echo apcu_fetch($key).PHP_EOL;
 
apcu_delete($key);
 
echo "apcu_delete->apcu_fetch 결과:";
echo apcu_fetch($key).PHP_EOL;
 
// -- 결과 --
// 7.3.27
// apcu_store->apcu_fetch 결과:7.3.27hello
// apcu_delete->apcu_fetch 결과:
 
// 8.1.8
// apcu_store->apcu_fetch 결과:8.1.8hello
// apcu_delete->apcu_fetch 결과:

타입 자동 변환 (bool → Array) deprecated

  • bool 타입으로 초기화 된 것을 Array로 셋팅하여 사용할 때 자동으로 Array로 변환해 주던 것 deprecated
<?php
 
echo phpversion().PHP_EOL; // 테스트 스크립트 돌린 php버전 확인용
 
/** @var int[] $a */
$a = FALSE; // bool 타입으로 초기화 후
 
if (isset($a[1]) == false)
{
    $a[1] = 1; // 배열로 변환하여 사용함
}
 
// 8.1.8 : Deprecated: Automatic conversion of false to array is deprecated in /var/www/html/test.php on line 12
profile
프로그래머

0개의 댓글