cari

Rumah  >  Soal Jawab  >  teks badan

memerlukan kaedah mengembalikan int apabila tidak mungkin dalam PHP

<p>Saya mempunyai kod berikut yang menyimpan beberapa kod php pada fail dan kemudian memuatkannya dan menjalankannya semula dan kadangkala kaedah memerlukan mengembalikan int, mengapa ini berlaku? </p> <h1>demo.php</h1> <pre class="brush:php;toolbar:false;"><?php $f = function() use($a){ $cachePath = '/tmp/t.php'; $kod = '<?php'; $kod .= "nn"; $code .= 'return ' var_export([], benar) ';'; file_put_contents($cachePath, $code, LOCK_EX); if (file_exists($cachePath)) { // Kadang-kadang baris berikut mengembalikan int, kenapa? $result = memerlukan($cachePath); jika (!is_array($result)) { var_dump($result, $cachePath, file_get_contents($cachePath)); keluar("ok"); } var_dump($hasil); } }; untuk($i=0;$i<1000000;$i++) { $f(); }</pre> <h1>Bagaimana untuk membiak? </h1> <p>Gunakan dua proses php untuk menjalankan kod di atas</p> <pre class="brush:php;toolbar:false;">php demo.php</pre></p>
P粉883223328P粉883223328458 hari yang lalu590

membalas semua(2)saya akan balas

  • P粉351138462

    P粉3511384622023-09-03 09:03:54

    Ini adalah dokumentasi untuk require 的标准行为,与 include , tingkah laku adalah sama antara keduanya:

    Seperti yang anda lihat, apabila nilai pulangan tidak ditimpa, integer (1) dikembalikan pada laluan gembira.

    Ini masuk akal untuk contoh anda, setakat ini fail itu wujud (jadi tiada ralat maut), tetapi memandangkan fail itu baru dibuat, ia mungkin hanya dipotong, iaitu, ia kosong.

    Jadi nilai pulangan tidak ditimpa dan anda boleh melihat int(1).

    Penjelasan lain adalah secara semula jadi bahawa anda telah menulis ganti dengan integer, yang juga mungkin kerana berbilang proses boleh menulis ke fail yang sama, tetapi dengan cara anda menulis contoh anda, ia berkemungkinan kecil. Saya hanya menyebutnya kerana ia adalah satu lagi penjelasan yang sah.

    mengandungi jika ada

    Contoh cara menggantung syarat perlumbaan apabila anda mencari $result dan bukannya (hanya) apabila fail wujud:

    if (($result = @include($cachePath)) &&
        is_array($result)    
    ) {
       # $result is array, which is required
       # ...
    }
    

    Idea di sebaliknya ialah kami melakukan sedikit sahaja pengendalian ralat, seperti menyemak sama ada fail itu wujud, jika tidak, ia tidak boleh disertakan (include() hanya mengeluarkan amaran dan menyampaikannya dengan $result = false), dan kemudian jika $ keputusan dimuatkan ia berlaku untuk ujian is_array().

    Inilah yang kami ada untuk ralat, tetapi kami tahu apa yang kami cari, iaitu $result ialah tatasusunan.

    Ini selalunya dipanggil transaksi atau operasi transaksi.

    Dalam contoh baharu ini, kami tidak memasukkan badan sekiranya apabila tatasusunan $result kosong, iaitu tidak mengandungi sebarang data.

    Pada peringkat pemprosesan atur cara, yang mungkin menarik minat kami, kehadiran atau ketiadaan fail, kosong atau tidak kosong, atau ditulis secara salah adalah semua keadaan ralat yang perlu "dimakan" dan membatalkan $hasil.

    Ralat takrifan tidak wujud.

    Mengendalikan ralat penghuraian (untuk Sertakan-Jika-Wujud)

    Memandangkan PHP 7.0 kami boleh menggunakan include() dan jika malangnya fail include yang dikembalikan separuh ditulis kami akan melihat ralat penghuraian PHP yang boleh ditangkap:

    # start the transaction
    $result = null;
    assert(
        is_string($cachePath) &&           # pathnames are strings,
        '' !== $cachePath &&               # never empty,
        false === strpos($cachePath, "rrreee") # and must not contain null-bytes
    );
    try {
        if (file_exists($cachePath)) {
            $result = include($cachePath);
        }
        # invalidate $result in case include() did technically work.
        if (!$result || !is_array($result) {
            $result = null;
        }
    } catch (Throwable $t) {
        # catch all errors and exceptions,
        # the fall-through is intended to invalidate $result.
        $result = null;
    } finally {
        # $result is not null, but a non-empty array if it worked.
        # $result is null, if it could not be acquired.
    }
    

    Sila rujuk PHP try-catch-finally untuk mengetahui cara membuang pengecualian/kerja pengendalian pengecualian secara terperinci, assert() digunakan untuk merekodkan maksud parameter input $cachePath dalam contoh.

    Contoh kedua tidak menggunakan operasi penindasan "@", sebabnya jika anda menggunakannya seperti contoh sebelumnya, dan fail yang akan disertakan akan mengandungi ralat fatal sebenar, ralat maut akan disenyapkan. Pada masa kini, dalam PHP moden, ini bukan masalah besar lagi, tetapi menggunakan file_exists() + include() - walaupun terdapat syarat perlumbaan kerana menyemak masa vs masa penggunaan - selamat (hanya amaran) untuk fail yang tidak wujud dan Ralat maut tidak disembunyikan.

    Seperti yang anda lihat, semakin banyak butiran yang anda ketahui, semakin sukar untuk menulis kod yang kalis masa hadapan yang mungkin. Kita tidak boleh tersesat dalam pengendalian ralat itu sendiri, tetapi harus menumpukan pada keputusan dan menentukan bahawa ralat ini tidak wujud.

    Yang berkata, include() masih menyebabkan data dimuatkan ke dalam memori, file_exists() hanya digunakan untuk "menindas" amaran, kita tahu bahawa, walau bagaimanapun, include() mungkin mengeluarkan amaran dan mungkin mengembalikan integer dan bukannya satu tatasusunan .


    Sekarang, memandangkan pengaturcaraan adalah sukar: anda kemudian boleh membungkusnya dalam satu gelung dan katakan cuba semula tiga kali. Mengapa tidak menggunakan untuk gelung untuk mengira dan melindungi percubaan semula berangka?

    balas
    0
  • P粉550323338

    P粉5503233382023-09-03 00:09:17

    Isu ini tidak boleh diterbitkan semula jika skrip sentiasa mempunyai hanya seorang pelaksana.

    Jika anda bercakap tentang menjalankan skrip ini secara selari, masalahnya ialah menulis fail dalam mod eksklusif tidak melindungi anda daripada membaca fail kemudian semasa proses penulisan.

    Proses mungkin menulis ke fail (dan memiliki kunci), tetapi require tidak menghormati kunci (kunci sistem fail adalah nasihat, tidak dikuatkuasakan).

    Jadi penyelesaian yang betul ialah:

    <?php
    
    $f = function()  use($a){
        $cachePath = '/tmp/t.php';
    
        /* Open the file for writing only. If the file does not exist, it is created.
           If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x').
           The file pointer is positioned on the beginning of the file. 
           This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file, as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested). */
        $fp = fopen($cachePath, "c");
    
        $code = '<?php';
        $code .= "\n\n";
        $code .= 'return ' . var_export([], true) . ';';
     
        // acquire exclusive lock, waits until lock is acquired
        flock($fp, LOCK_EX);
        // clear the file
        ftruncate($fp, 0);
        // write the contents
        fwrite($fp, $code);
    
        //wrong (see my answer as to why)
        //file_put_contents($cachePath, $code, LOCK_EX);
    
        //not needed
        //if (file_exists($cachePath)) {
            // Lock is held during require
            $result = require($cachePath);
            if (!is_array($result)) {
                var_dump($result, $cachePath, file_get_contents($cachePath));
                exit("ok");
            }
            var_dump($result);
        //}
        // closing the file implicitly releases the lock
        fclose($fp);
    };
    
    
    for($i=0;$i<1000000;$i++) {
        $f();
    }
    

    Perhatikan bahawa kunci tidak dilepaskan dan diperoleh semula selepas menulis, kerana proses lain mungkin menunggu untuk menulis ganti fail.

    Tidak menyiarkannya untuk memastikan sekeping kod yang sama ditulis juga required.

    Walau bagaimanapun, semua perkara ini dipersoalkan dari awal.

    Mengapa saya perlu menulis ke fail supaya ia boleh dikembalikan kemudian require?

    balas
    0
  • Batalbalas