Jump to content
php.lv forumi

isset vs @, jeb, Kāpēc tā notiek?


aaxc

Recommended Posts

Mums te darbā panesās maza diskusija par to, vai lietot @ vai labāk tomēr isset(), un gribēju padalīties ar secinājumiem.

 

Pēc īsiem testiem ātri noskaidrojām uzvarētāju:

Execution times: 10'000'000
17.041812181473 seconds. [ @ ]
1.7088520526886 seconds. [ isset() ]
1.775101184845 seconds.  [ isset() && var ]
1.7850821018219 seconds. [ isset() AND var ]
1.8156411647797 seconds. [ isset() && !empty(var) ]
1.7943229675293 seconds. [ isset() AND !empty(var) ]
1.7861270904541 seconds. [ !empty(var) ]

Uzreiz radās jautājums, kāpēc tieši tā. Tika pārlasīts vēlreiz manuālis, bet gala atbilde tā arī netika iegūta.

 

PHP supports one error control operator: the at sign (@). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.

Ir rakstīts, ka iespējamie errori tiek ignorēti, bet nav 100% minēts, ka tie vispar tiek ģenerēti. Bet, protams, apskatot testa rezultātus, var secināt ka tiek gan ( laigan precīzas atbildes par to nav, ir tikai atsauksmes ).

 

Pirms tam tika patestēts arī ar izslēgtu error_reportingu kopumā, kur starpība bija stipri mazāka, bet tomēr bija, ir jākonstatē, ka errors vienmēr tiek triggerots, tikai pie izslēgtiem error_reporting tiek piefixēts fakts, ka bija kļūda, bez pašas kļūdas izveidošanas un otrajā gadījumā ( ar ieslēgtu error_reportingu ), tā tiek uzģenerēta pilnībā, bet netiek izvadīta ( bik atgādina veco dos stilu ).

 

Un vēl mazs interesants fakts, ifs AND !empty izpildās nezkāpēc mazliet ātrāk kā && !empty, laigan ar vienkāršu $var ( bez !empty ) pārbaudi notiek pretējais.

Link to comment
Share on other sites

@ ir kļūdu izvades operators. Vienīgais pieļaujamais šī operatora pielietojums - supresēt kļūdas funkcijām, kuras tu nekontrolē. Piemēram, nu jau novecojušais mysql_connect izmet wārnu ik reizes, kad nevar savienoties. Tu šo izvadi nevari aizvākt ne kā savādak, kā lietojot @ vai manuāli supresējot kļūdas lokāli mainot display errors. Šis ir vienīgais pareizais @ lietojums. 

 

@ ir tik lēns tāpēc, ka tas iekšēji supresē tikai un vienīgi kļūdu izvadi izmantojot izvades buferēšanu. 

 

Par && un AND varu paskaidrot - && un AND atšķiras precedences līmeņi un tie tiek apstrādāti mazliet savādak. Piemēram, $var = false and true, $var būs true, bet $var = false && true būs true. Hence niecīgas atšķirības izpildē. Parasti visur lieto &&. 

Link to comment
Share on other sites

Par nelietošanu vari man nestāstīt, diskusija sākās tanī brīdi, kad es saķu lamāties, ka visās malās @ sabāzsts un paliek jau slikti šamos visu laiku vākt ārā.
 

@ ir tik lēns tāpēc, ka tas iekšēji supresē tikai un vienīgi kļūdu izvadi izmantojot izvades buferēšanu.

Tik tālu es arī esmu sapratis, tikai nevaru atrast nevienu tiešu pierādījumu + jautājums, kāpēc ar izslēgtiem error_reporting ( kur Notice netiek veidota ), tik un tā šis laiks ir ilgāks.

Link to comment
Share on other sites

[ isset() && !empty(var) ]
[ isset() AND !empty(var) ]

 

šeit pietiek ar !empty(), isset() nav nepieciešams - iegūsi vēl nedaudz laiku.

 

 

ar && un AND ir tā, ka secība atšķiras:

$a = true && false;
$b = true and false;
echo "a=$a ; b=$b";

 

 

Rezultāts:

a= ; b=1

 

 

 

T.i. izpilda: 

($b = true) and false;
Link to comment
Share on other sites

Vienīgā vieta, kur tam varēja atrast pieradījumu ir php source. Esmu jau aizmirsis kur, un 5 min meklēšana nepalīdzēja. Oh well. 

Buutu labi, ja pateiktu aptuveno virzienu, kur to mekleet. Pamekleeshu.

Link to comment
Share on other sites

Ar to @ ir tā, ka tas, ka kļūdu paziņojumus neizvada, vēl nenozīmē, ka tos tiešām neizvada.

Daudz atkarīgs no PHP konfigurācijas. Piemēram, kļūdu paziņojumus turpinās mest ne uz ekrāna, bet uz error.log, t.i. @ attiecas tikai uz izvadīšanu uz ekrānu.

Ja php.ini (vai ar ini_set) uzsetosi scream.enabled, tad kļūdas paziņojums uz ekrāna tiks izvadīts par spīti @.

 

Tur tas mehānisms bija apmēram tāds, ka kļūdas paziņojums tiek sagatavots vienmēr, bet pēcāk notiek pārdomas, kur to nolikt. Ja kodā ir @ ir jāsagatavojas pēdējā brīdī savākt paziņojumu atpakaļ, neskatoties uz php konfigurāciju, jo konfigurāciju var izmainīt pilnīgi negaidīti ar ini_set. Tur arī rodas bremzes.

Link to comment
Share on other sites

Bik pastījos. Tātad:

 

 '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; }
 

Tālāk

 

void zend_do_begin_silence(znode *strudel_token TSRMLS_DC)
{
        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

        opline->opcode = ZEND_BEGIN_SILENCE;
        opline->result.op_type = IS_TMP_VAR;
        opline->result.u.var = get_temporary_variable(CG(active_op_array));
        SET_UNUSED(opline->op1);
        SET_UNUSED(opline->op2);
        *strudel_token = opline->result;
}


void zend_do_end_silence(znode *strudel_token TSRMLS_DC)
{
        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

        opline->opcode = ZEND_END_SILENCE;
        opline->op1 = *strudel_token;
        SET_UNUSED(opline->op2);
}

 

Ko dara opcodi ZEND_BEGIN_SILENCE un ZEND_END_SILENCE?

 

 

static int ZEND_FASTCALL  ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
        USE_OPLINE

        SAVE_OPLINE();
        Z_LVAL(EX_T(opline->result.var).tmp_var) = EG(error_reporting);
        Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_LONG;  /* shouldn't be necessary */
        if (EX(old_error_reporting) == NULL) {
                EX(old_error_reporting) = &EX_T(opline->result.var).tmp_var;
        }

        if (EG(error_reporting)) {
                do {
                        EG(error_reporting) = 0;
                        if (!EG(error_reporting_ini_entry)) {
                                if (UNEXPECTED(zend_hash_find(EG(ini_directives), "error_reporting", sizeof("error_reporting"), (void **) &EG(error_reporting_ini_entry)) == FAILURE)) {
                                        break;
                                }
                        }
                        if (!EG(error_reporting_ini_entry)->modified) {
                                if (!EG(modified_ini_directives)) {
                                        ALLOC_HASHTABLE(EG(modified_ini_directives));
                                        zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
                                }
                                if (EXPECTED(zend_hash_add(EG(modified_ini_directives), "error_reporting", sizeof("error_reporting"), &EG(error_reporting_ini_entry), sizeof(zend_ini_entry*), NULL) == SUCCESS)) {
                                        EG(error_reporting_ini_entry)->orig_value = EG(error_reporting_ini_entry)->value;
                                        EG(error_reporting_ini_entry)->orig_value_length = EG(error_reporting_ini_entry)->value_length;
                                        EG(error_reporting_ini_entry)->orig_modifiable = EG(error_reporting_ini_entry)->modifiable;
                                        EG(error_reporting_ini_entry)->modified = 1;
                                }
                        } else if (EG(error_reporting_ini_entry)->value != EG(error_reporting_ini_entry)->orig_value) {
                                efree(EG(error_reporting_ini_entry)->value);
                        }
                        EG(error_reporting_ini_entry)->value = estrndup("0", sizeof("0")-1);
                        EG(error_reporting_ini_entry)->value_length = sizeof("0")-1;
                } while (0);
        }
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
}

static int ZEND_FASTCALL  ZEND_END_SILENCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
        USE_OPLINE
        zval restored_error_reporting;

        SAVE_OPLINE();
        if (!EG(error_reporting) && Z_LVAL(EX_T(opline->op1.var).tmp_var) != 0) {
                Z_TYPE(restored_error_reporting) = IS_LONG;
                Z_LVAL(restored_error_reporting) = Z_LVAL(EX_T(opline->op1.var).tmp_var);
                EG(error_reporting) = Z_LVAL(restored_error_reporting);
                convert_to_string(&restored_error_reporting);
                if (EXPECTED(EG(error_reporting_ini_entry) != NULL)) {
                        if (EXPECTED(EG(error_reporting_ini_entry)->modified &&
                            EG(error_reporting_ini_entry)->value != EG(error_reporting_ini_entry)->orig_value)) {
                                efree(EG(error_reporting_ini_entry)->value);
                        }
                        EG(error_reporting_ini_entry)->value = Z_STRVAL(restored_error_reporting);
                        EG(error_reporting_ini_entry)->value_length = Z_STRLEN(restored_error_reporting);
                } else {
                        zendi_zval_dtor(restored_error_reporting);
                }
        }
        if (EX(old_error_reporting) == &EX_T(opline->op1.var).tmp_var) {
                EX(old_error_reporting) = NULL;
        }
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
}


 

Vienvārdsakot - kauko ņemās. Tālāk jau ņem profileri un meklē "vājās" vietas - es tam esmu par slinku :D

Link to comment
Share on other sites

Nu rekur jau arī ir, ja šī ir īstā vieta, tad 

 

EG(error_reporting_ini_entry)->orig_value = EG(error_reporting_ini_entry)->value;
                                        EG(error_reporting_ini_entry)->orig_value_length = EG(error_reporting_ini_entry)->value_length;
                                        EG(error_reporting_ini_entry)->orig_modifiable = EG(error_reporting_ini_entry)->modifiable;
                                        EG(error_reporting_ini_entry)->modified = 1;
Link to comment
Share on other sites

Gribu piebilst, ka issetus bezjēgā lietot arī nav risinājums. Ja mainīgajam jābūt definētam, tad issetu nevajadzētu lietot, lai pamanītu situācju, kad tas tā ir.

 

Nezinu, kādā informatīvajā telpā uzturaties jūs, bet tas, ka @ izslēdz error reportingu, izpilda kodu un ieslēdz atpakaļ, man šķiet, ir lasīts vairāk kā 10x pat negribot, vienkārši garāmejot tiek pieminēts.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...