source

예외:'닫힘'을(를) 직렬화할 수 없습니다.

lovecheck 2023. 10. 14. 10:20
반응형

예외:'닫힘'을(를) 직렬화할 수 없습니다.

그래서 정확히 무엇을 보여드려야 할지 잘 모르겠습니다만, 코드가 더 필요하시면 주저하지 마시고 질문해 주시기 바랍니다.

따라서 이 방법을 사용하면 응용 프로그램 내에서 initMailer for Zend를 설정할 수 있습니다.

protected function _initMailer()
{
    if ('testing' !==  APPLICATION_ENV) {
        $this->bootstrap('Config');
        $options = $this->getOptions();
        $mail = new Zend_Application_Resource_Mail($options['mail']);
    }elseif ('testing'  ===  APPLICATION_ENV) {
        //change the mail transport only if dev or test
        if (APPLICATION_ENV <> 'production') {

            $callback = function()
            {
                return 'ZendMail_' . microtime(true) .'.tmp';
            };

            $mail = new Zend_Mail_Transport_File(
                array('path' => '/tmp/mail/',
                        'callback'=>$callback
                )
            );

            Zend_Mail::setDefaultTransport($mail);
        }
    }


    return $mail;
}

안에 있는 닫힘을 볼 수 있습니다.이 코드를 사용하는 테스트를 실행하면 다음과 같이 표시됩니다.

Exception: Serialization of 'Closure' is not allowed 

따라서 이 "폐쇄"와 관련된 모든 테스트는 실패합니다.그래서 여러분들께 어떻게 하면 좋을지 여쭤보려고 합니다.

위의 내용을 명확히 하기 위해 우리가 보내는 모든 이메일은 그 이메일에 대한 정보를 /tmp/mail/ 디렉토리의 폴더에 파일로 저장하기를 원한다는 것뿐이었습니다.

익명 기능을 직렬화할 수 없습니다.

$function = function () {
    return "ABC";
};
serialize($function); // would throw error

코드에 따라 Closure(폐쇄를 사용하고 있습니다.

$callback = function () // <---------------------- Issue
{
    return 'ZendMail_' . microtime(true) . '.tmp';
};

해결책 1 : 정상적인 기능으로 대체

function emailCallback() {
    return 'ZendMail_' . microtime(true) . '.tmp';
}
$callback = "emailCallback" ;

솔루션 2 : 배열 변수에 의한 간접 메서드 호출

http://docs.mnkras.com/libraries_23rdparty_2_zend_2_mail_2_transport_2file_8php_source.html 을 보시면요.

   public function __construct($options = null)
   63     {
   64         if ($options instanceof Zend_Config) {
   65             $options = $options->toArray();
   66         } elseif (!is_array($options)) {
   67             $options = array();
   68         }
   69 
   70         // Making sure we have some defaults to work with
   71         if (!isset($options['path'])) {
   72             $options['path'] = sys_get_temp_dir();
   73         }
   74         if (!isset($options['callback'])) {
   75             $options['callback'] = array($this, 'defaultCallback'); <- here
   76         }
   77 
   78         $this->setOptions($options);
   79     }

동일한 접근 방식을 사용하여 콜백을 전송할 수 있습니다.

$callback = array($this,"aMethodInYourClass");

PHP에서는 직접 폐쇄 직렬화가 허용되지 않습니다.그러나 PHP Super Closure : https://github.com/jeremeamia/super_closure 같은 강력한 클래스를 사용할 수 있습니다.

이 클래스는 사용이 매우 간단하며 큐 관리자를 위한 래라벨 프레임워크에 번들로 제공됩니다.

github 문서에서:

$helloWorld = new SerializableClosure(function ($name = 'World') use ($greeting) {
    echo "{$greeting}, {$name}!\n";
});

$serialized = serialize($helloWorld);

이미 기술된 바와 같이, 박스 밖의 폐쇄는 직렬화할 수 없습니다.

하지만 사용하는 것은.__sleep(),__wakeup()마법 방법과 반사를 통해 수동으로 닫힘을 직렬화할 수 있습니다.자세한 내용은 확장-php-5-3-closures-serialization-및 reflection을 참조하십시오.

이것은 reflection과 php function eval을 사용합니다.이것은 코드 주입의 가능성을 열어주는 것이므로, 당신이 연재하고 있는 것에 유의하시기 바랍니다.

Globals를 비활성화해야 합니다.

 /**
 * @backupGlobals disabled
 */

안전하지는 않지만 실험적입니다. 비활성화될 수 있는 evalu()를 사용해야 하는 것과 같은 여러 가지 위험이 있습니다.가장 좋은 것은 hedoc 예제에서 당신의 스크립트를 serialized에 쓰는 것일 것입니다.

$code = <<<CODE
 <?php
class \$gen_class_{$user}{
 ...
}
CODE;

코드를 직렬화하거나 확장자 '.class.php'로 작성하여 코드를 보다 쉽게 사용할 수 있습니다. 스크립트를 쉽게 호출하여 영구적으로 만들 수 있습니다.

https://3v4l.org/jpHm9 업데이트 PHP 8

<?php

function closure_to_str($func)
{
    $refl = new \ReflectionFunction($func); // get reflection object
    $path = $refl->getFileName();  // absolute path of php file
    $begn = $refl->getStartLine(); // have to `-1` for array index
    $endn = $refl->getEndLine();
    $dlim = PHP_EOL;
    $list = explode($dlim, file_get_contents($path));         // lines of php-file source
    $list = array_slice($list, ($begn-1), ($endn-($begn-1))); // lines of closure definition
    $last = (count($list)-1); // last line number

    if((substr_count($list[0],'function')>1)|| (substr_count($list[0],'{')>1) || (substr_count($list[$last],'}')>1))
    { throw new \Exception("Too complex context definition in: `$path`. Check lines: $begn & $endn."); }

    $list[0] = ('function'.explode('function',$list[0])[1]);
    $list[$last] = (explode('}',$list[$last])[0].'}');


    return implode($dlim,$list);
}

$test = 10;
$dog2 = function($var=0) use ($test){ 
    $var = 10;
    echo $var . PHP_EOL;
    return $test . $var;
};

echo closure_to_str($dog2)."\n\n";

반환 문자열

function($var=0) use ($test){ 
    $var = 10;
    echo $var . PHP_EOL;
    return $test . $var;
}

언급URL : https://stackoverflow.com/questions/13734224/exception-serialization-of-closure-is-not-allowed

반응형