أقوم بتشغيل PHP برنامج نصي ، ومواصلة تلقي أخطاء مثل:
إشعار: متغير غير معروف: my_variable_name في C:\wamp\www\mypath\index.php على السطر 10
إشعار: فهرس غير محدد: my_index C:\wamp\www\mypath\index.php على السطر 11
يبدو السطر 10 و 11 هكذا:
echo "My variable value is: " . $my_variable_name;
echo "My index value is: " . $my_array["my_index"];
ما معنى رسائل الخطأ هذه؟
لماذا تظهر فجأة؟ اعتدت على استخدام هذا البرنامج النصي لسنوات ولم يسبق لي أن واجهت أي مشكلة.
كيف يمكنني إصلاحها؟
هذا هو السؤال المرجعي العام بالنسبة للأشخاص للربط به كمكرر ، بدلاً من الاضطرار إلى شرح المشكلة مرارًا وتكرارًا. أشعر أن هذا ضروري لأن معظم إجابات العالم الحقيقي حول هذه المسألة محددة للغاية.
مناقشة التعريف ذات الصلة:
من الحكمة الواسعة لـ PHP Manual :
يعد الاعتماد على القيمة الافتراضية لمتغير غير مهيأ مشكلة في حالة تضمين ملف واحد في ملف آخر يستخدم نفس اسم المتغير. إنها أيضًا مخاطرة كبيرة الأمان مع register_globals قيد التشغيل. E_NOTICE خطأ المستوى يصدر في حالة العمل مع متغيرات غير مهيأة ، ولكن ليس في حالة إلحاق عناصر بالصفيف غير المهيأ. isset () لغة البناء يمكن استخدامها للكشف عما إذا كان قد تم بالفعل تهيئة متغير. بالإضافة إلى ذلك ، فإن الحل هو فارغة () لأنه لا ينشئ رسالة تحذير أو خطأ إذا لم تتم تهيئة المتغير.
من PHP التوثيق :
لا يتم إنشاء تحذير في حالة عدم وجود المتغير. هذا يعني فارغة () هي في الأساس المعادل المختصر لـ! isset ($ var) || $ var == false .
هذا يعني أنه يمكنك استخدام empty()
فقط لتحديد ما إذا كان المتغير مضبوطًا ، بالإضافة إلى أنه يتحقق من المتغير مقابل ما يلي ، 0,"",null
.
مثال:
$o = [];
@$var = ["",0,null,1,2,3,$foo,$o['myIndex']];
array_walk($var, function($v) {
echo (!isset($v) || $v == false) ? 'true ' : 'false';
echo ' ' . (empty($v) ? 'true' : 'false');
echo "\n";
});
اختبر المقتطف أعلاه في 3v4l.org عبر الإنترنت PHP المحرر
على الرغم من أن PHP لا تتطلب إعلانًا متغيرًا ، إلا أنه يوصي به لتجنب بعض الثغرات الأمنية أو الأخطاء حيث ينسى المرء إعطاء قيمة للمتغير الذي سيتم استخدامه لاحقًا في البرنامج النصي. ما يفعله PHP في حالة المتغيرات غير المعلنة هو إصدار خطأ مستوى منخفض جدًا ، E_NOTICE
، خطأ لا يتم الإبلاغ عنه بشكل افتراضي ، لكن الدليل ينصح بالسماح أثناء التطوير.
طرق التعامل مع المشكلة:
مستحسن: قم بتعريف المتغيرات الخاصة بك ، على سبيل المثال عند محاولة إلحاق سلسلة بمتغير غير معروف. أو استخدم isset()
/ !empty()
للتحقق مما إذا كانت قد أعلنت قبل الرجوع إليها ، كما في:
//Initializing variable
$value = ""; //Initialization value; Examples
//"" When you want to append stuff later
//0 When you want to add numbers later
//isset()
$value = isset($_POST['value']) ? $_POST['value'] : '';
//empty()
$value = !empty($_POST['value']) ? $_POST['value'] : '';
لقد أصبح هذا أكثر نظافة اعتبارًا من PHP 7.0 ، الآن يمكنك استخدام عامل التماسك الخالي :
// Null coalesce operator - No need to explicitly initialize the variable.
$value = $_POST['value'] ?? '';
قم بتعيين معالج خطأ مخصص لـ E_NOTICE وإعادة توجيه الرسائل بعيدًا عن الإخراج القياسي (ربما إلى ملف سجل):
set_error_handler('myHandlerForMinorErrors', E_NOTICE | E_STRICT)
تعطيل E_NOTICE من التقارير. طريقة سريعة لاستبعاد E_NOTICE
هي:
error_reporting( error_reporting() & ~E_NOTICE )
قمع الخطأ مع @ المشغل .
ملاحظة: يوصى بشدة بتطبيق النقطة 1 فقط.
يظهر هذا الإشعار عندما تحاول (أو PHP) الوصول إلى فهرس غير محدد للصفيف.
طرق التعامل مع المشكلة:
تحقق من وجود الفهرس قبل الوصول إليه. لهذا يمكنك استخدام isset()
أو array_key_exists()
:
//isset()
$value = isset($array['my_index']) ? $array['my_index'] : '';
//array_key_exists()
$value = array_key_exists('my_index', $array) ? $array['my_index'] : '';
قد ينشئ بناء اللغة list()
هذا عندما يحاول الوصول إلى فهرس صفيف غير موجود:
list($a, $b) = array(0 => 'a');
//or
list($one, $two) = explode(',', 'test string');
يتم استخدام متغيرين للوصول إلى عنصري صفيف ، ومع ذلك هناك عنصر صفيف واحد فقط ، الفهرس 0
، لذلك سيتم إنشاء:
إشعار: غير محدد الإزاحة: 1
$_POST
/$_GET
/$_SESSION
تظهر الإشعارات أعلاه غالبًا عند العمل مع $_POST
أو $_GET
أو $_SESSION
. بالنسبة لـ $_POST
و $_GET
، عليك فقط التحقق مما إذا كان الفهرس موجودًا أم لا قبل استخدامه. بالنسبة لـ $_SESSION
، يتعين عليك التأكد من بدء الجلسة بـ session_start()
وأن الفهرس موجود أيضًا.
لاحظ أيضًا أن جميع المتغيرات الثلاثة هي superglobals وهي كبيرة.
ذات صلة:
جرب هذا
Q1: يعني هذا الإشعار لم يتم تعريف $ varname في النطاق الحالي للبرنامج النصي.
Q2: استخدام شروط isset () ، فارغة () قبل استخدام أي متغير مشبوه يعمل بشكل جيد.
// recommended solution for recent PHP versions
$user_name = $_SESSION['user_name'] ?? '';
// pre-7 PHP versions
$user_name = '';
if (!empty($_SESSION['user_name'])) {
$user_name = $_SESSION['user_name'];
}
أو كحل سريع وقذّر:
// not the best solution, but works
// in your php setting use, it helps hiding site wide notices
error_reporting(E_ALL ^ E_NOTICE);
ملاحظة حول الجلسات:
عند استخدام الجلسات ، يجب وضع session_start();
داخل جميع الملفات باستخدام الجلسات.
@
operatorبالنسبة للإشعارات غير المرغوب فيها والمتكررة ، يمكن استخدام المشغل المخصص @
إلى "إخفاء" رسائل متغير/فهرس غير محددة.
$var = @($_GET["optional_param"]);
isset?:
أو ??
super-suctionion. إشعارات لا يزال يمكن الحصول على تسجيل. وقد يقوم أحدهم بإحياء الإشعارات الخفية @
- مع: set_error_handler("var_dump");
if (isset($_POST["shubmit"]))
في الكود الأولي.@
أو isset
فقط بعد التحقق من الوظيفة.إصلاح السبب الأول. ليس الإشعارات.
@
مقبول بشكل أساسي لمعلمات الإدخال $_GET
/$_POST
، وتحديدا إذا كانت اختيارية .وبما أن هذا يغطي معظم هذه الأسئلة ، فلنوسع في أكثر الأسباب شيوعًا:
$_GET
/$_POST
/$_REQUEST
إدخال غير محددأول شيء تقوم به عند مواجهة فهرس/إزاحة غير محدد ، هو التحقق من الأخطاء المطبعية:$count = $_GET["whatnow?"];
ثانياً ، إذا لم يكن للإشعار سبب واضح ، فاستخدم var_dump
أو print_r
للتحقق الكل صفيف الإدخال للمحتوى الحالي:
var_dump($_GET);
var_dump($_POST);
//print_r($_REQUEST);
كلاهما سيكشف ما إذا كان قد تم استدعاء البرنامج النصي الخاص بك مع أي معلمات على اليمين أم لا.
البديل أو إضافة إلى ذلك استخدام devtools المتصفح (F12) وفحص علامة تبويب الشبكة للطلبات والمعلمات:
سيتم عرض معلمات POST وإدخال GET بشكل منفصل.
بالنسبة إلى معلمات $_GET
، يمكنك أيضًا إلقاء نظرة خاطفة على QUERY_STRING
in
print_r($_SERVER);
PHP لديه بعض القواعد إلى توحيد أسماء المعلمات غير القياسية في superglobals. أباتشي قد تفعل بعض إعادة كتابة كذلك. يمكنك أيضًا الاطلاع على $_COOKIES
الخام المرفق ورؤوس طلب HTTP الأخرى بهذه الطريقة.
من الواضح أن ننظر إلى شريط عنوان المتصفح الخاص بك عن معلمات GET :
http://example.org/script.php?id=5&sort=desc
أزواج name=value
بعد علامة الاستفهام ?
هي معلمات طلب البحث (GET). وبالتالي ، قد يؤدي عنوان URL هذا إلى $_GET["id"]
و $_GET["sort"]
فقط.
أخيرًا تحقق من <form>
و <input>
التصريحات ، إذا كنت تتوقع معلمة لكنك لا تتلقى شيئًا.
<input name=FOO>
id=
أو title=
.method=POST
$_POST
.method=GET
(أو تتركه خارجًا) قد ينتج عنه متغيرات $_GET
.action=script.php?get=param
عبر $ _GET وحقول method=POST
المتبقية في $ _POST جنبًا إلى جنب.$_REQUEST['vars']
مرة أخرى ، وهو ما يهرس GET و POST المعلمات.إذا كنت تستخدم mod_rewrite ، فعليك التحقق من كل من access.log
بالإضافة إلى تمكين RewriteLog
لمعرفة المعلمات الغائبة.
$_FILES
$_FILES["formname"]
.enctype=multipart/form-data
method=POST
في إعلان <form>
الخاص بك.$_COOKIE
$_COOKIE
أبدًا بعد setcookie()
، ولكن فقط على أي طلب HTTP للمتابعة.عموما بسبب "البرمجة السيئة" ، واحتمال الأخطاء الآن أو في وقت لاحق.
if (isset($varname))
، قبل استخدامهاهذا يعني أنك تقوم باختبار أو تقييم أو طباعة متغير لم تقم بتعيين أي شيء له بعد. هذا يعني أن لديك خطأ مطبعي ، أو تحتاج إلى التحقق من تهيئة المتغير إلى شيء أولاً. تحقق من مسارات المنطق الخاصة بك ، وقد يتم تعيينها في مسار واحد ولكن ليس في مسار آخر.
لم أكن أريد تعطيل الإشعارات لأنها مفيدة ، لكنني أردت تجنب الكثير من الكتابة.
وكان حل بلدي هذه الوظيفة:
function ifexists($varname)
{
return(isset($$varname)?$varname:null);
}
لذلك إذا أردت الإشارة إلى اسم $ والصدى في حالة وجوده ، فأنا ببساطة أكتب:
<?=ifexists('name')?>
لعناصر الصفيف:
function ifexistsidx($var,$index)
{
return(isset($var[$index])?$var[$index]:null);
}
في الصفحة إذا كنت أريد أن أشير إلى $ _REQUEST ['name']:
<?=ifexistsidx($_REQUEST,'name')?>
أفضل طريقة للحصول على إدخال سلسلة هي:
$value = filter_input(INPUT_POST, 'value');
يكافئ هذا الخط الواحد:
if (!isset($_POST['value'])) {
$value = null;
} elseif (is_array($_POST['value'])) {
$value = false;
} else {
$value = $_POST['value'];
}
إذا كنت تريد سلسلة قيمة ، تمامًا مثل:
$value = (string)filter_input(INPUT_POST, 'value');
ردًا على "" لماذا تظهر فجأة؟ اعتدت استخدام هذا البرنامج النصي لسنوات ولم أواجه أي مشكلة على الإطلاق. "
من الشائع جدًا أن تعمل معظم المواقع في إطار الإبلاغ عن الأخطاء "الافتراضي" عن "إظهار جميع الأخطاء ، ولكن ليس" الإشعارات "و" المهملة ". سيتم تعيين ذلك في php.ini وسيتم تطبيقه على جميع المواقع على الخادم. هذا يعني أن تلك "الإشعارات" المستخدمة في الأمثلة سيتم إخمادها (مخفية) بينما سيتم عرض/تسجيل الأخطاء الأخرى ، التي تعتبر أكثر أهمية.
الإعداد الحاسم الآخر هو أن الأخطاء يمكن إخفاؤها (على سبيل المثال ، display_errors
مضبوط على "off" أو "syslog").
ما سيحدث في هذه الحالة هو أنه تم تغيير error_reporting
أيضًا لإظهار الإشعارات (وفقًا للأمثلة) و/أو تغيير الإعدادات إلى display_errors
على الشاشة (على عكس منعها/تسجيلها).
لماذا غيروا؟
الإجابة الواضحة/الأبسط هي أن شخصًا ما قام بضبط أي من هذه الإعدادات في php.ini ، أو نسخة مطورة من PHP يستخدم الآن php.ini مختلفًا من قبل. هذا هو المكان الأول للنظر.
ومع ذلك فمن الممكن أيضًا تجاوز هذه الإعدادات في
وأي من هذه يمكن أيضا أن تتغير.
هناك أيضًا المضاعفات الإضافية المتمثلة في أن تكوين خادم الويب يمكنه تمكين/تعطيل توجيهات htaccess ، لذلك إذا كان لديك توجيهات في .htaccess تبدأ فجأة/تتوقف عن العمل ، فأنت بحاجة إلى التحقق من ذلك.
(.htconf/.htaccess تفترض أنك تعمل باسم Apache. إذا كان تشغيل سطر الأوامر لن ينطبق هذا ؛ إذا كان يتم تشغيل IIS أو خادم ويب آخر ، فستحتاج إلى التحقق من هذه التكوينات وفقًا لذلك)
ملخص
error_reporting
و display_errors
php في php.ini لم تتغير ، أو أنك لا تستخدم php.ini مختلفة من قبل.error_reporting
و display_errors
php في .htconf (أو vhosts وما إلى ذلك) لم يتغيراerror_reporting
و display_errors
php في .htaccess لم تتغيرerror_reporting
و display_errors
php هناك.لأن المتغير '$ user_location' لا يتم تعريفه. إذا كنت تستخدم أي حلقة إذا كنت داخلها تعلن عن متغير "$ user_location" ، فيجب أن يكون لديك أيضًا حلقة أخرى وتعريفها. فمثلا:
$a=10;
if($a==5) { $user_location='Paris';} else { }
echo $user_location;
ستنشئ الشفرة أعلاه خطأ حيث لم يتم استيفاء حلقة if ولم يتم تعريف الحلقة الأخرى "$ user_location" في الحلقة الأخرى. لا يزال PHP طُلب منه صدى المتغير. لذلك لتعديل الكود ، يجب عليك القيام بما يلي:
$a=10;
if($a==5) { $user_location='Paris';} else { $user_location='SOMETHING OR BLANK'; }
echo $user_location;
الإصلاح السريع هو تعيين المتغير الخاص بك لإلغاء في الجزء العلوي من التعليمات البرمجية الخاصة بك
$user_location = null;
اعتدت أن ألعن هذا الخطأ ، لكن من المفيد أن أذكرك بالهروب من إدخال المستخدم.
على سبيل المثال ، إذا كنت تعتقد أن هذا رمز ذكي مختزل:
// Echo whatever the hell this is
<?=$_POST['something']?>
...فكر مرة اخرى! الحل الأفضل هو:
// If this is set, echo a filtered version
<?=isset($_POST['something']) ? html($_POST['something']) : ''?>
(يمكنني استخدام وظيفة html()
مخصصة للهروب من الحروف ، قد يختلف عدد الأميال المقطوعة)
يمكنني استخدام وظيفة مفيدة في كل الوقت exst () التي تعلن المتغيرات تلقائيا.
كودك سيكون -
$greeting = "Hello, ".exst($user_name, 'Visitor')." from ".exst($user_location);
/**
* Function exst() - Checks if the variable has been set
* (copy/paste it in any place of your code)
*
* If the variable is set and not empty returns the variable (no transformation)
* If the variable is not set or empty, returns the $default value
*
* @param mixed $var
* @param mixed $default
*
* @return mixed
*/
function exst( & $var, $default = "")
{
$t = "";
if ( !isset($var) || !$var ) {
if (isset($default) && $default != "") $t = $default;
}
else {
$t = $var;
}
if (is_string($t)) $t = trim($t);
return $t;
}
في PHP 7.0 ، أصبح من الممكن الآن استخدام عامل التضمين Null:
echo "My index value is: " . ($my_array["my_index"] ?? '');
يساوي:
echo "My index value is: " . (isset($my_array["my_index"]) ? $my_array["my_index"] : '');
بمرور الوقت ، أصبحت PHP لغة أكثر تركيزًا على الأمان. الإعدادات التي كان يتم إيقاف تشغيلها بشكل افتراضي يتم الآن تشغيلها افتراضيًا. مثال مثالي على ذلك هو E_STRICT
، الذي أصبح قيد التشغيل افتراضيًا اعتبارًا من PHP 5.4.0 .
علاوة على ذلك ، وفقًا لـ PHP الوثائق ، بشكل افتراضي ، يتم تعطيل E_NOTICE
في php.ini. PHP يوصي مستندات تشغيله لأغراض التصحيح . ومع ذلك ، عندما أقوم بتنزيل PHP من مستودع Ubuntu — ومن مكدس Windows BitNami — أرى شيئًا آخر.
; Common Values:
; E_ALL (Show all errors, warnings and notices including coding standards.)
; E_ALL & ~E_NOTICE (Show all errors, except for notices)
; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.)
; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors)
; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
; Development Value: E_ALL
; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
; http://php.net/error-reporting
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
لاحظ أنه تم تعيين error_reporting
فعليًا على قيمة الإنتاج افتراضيًا ، وليس على القيمة "الافتراضية" افتراضيًا. هذا مربك إلى حد ما ولا يتم توثيقه خارج php.ini ، لذلكلاقمت بالتحقق من صحة ذلك على توزيعات أخرى.
للإجابة على سؤالك ، يظهر هذا الخطأ الآن عندما لم يظهر من قبل لأنه:
قمت بتثبيت PHP والإعدادات الافتراضية الجديدة موثقة إلى حد ما ولكن لا تستبعد E_NOTICE
.
تساعد تحذيرات E_NOTICE
مثل المتغيرات غير المحددة والفهارس غير المحددة على جعل الشفرة أكثر نظافة وأمانًا. أستطيع أن أخبرك أنه ، منذ سنوات ، اضطرني حفظ E_NOTICE
إلى إعلان متغيراتي. لقد جعل الأمر أكثر سهولة لتعلم C ، ولم يكن إعلان المتغيرات أكبر من مصدر إزعاج.
قم بإيقاف تشغيل E_NOTICE
عن طريق نسخ "القيمة الافتراضية" E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
واستبدالها بما هو غير مكتمل حاليًا بعد تسجيلات الدخول في error_reporting =
. أعد تشغيل Apache ، أو PHP إذا كنت تستخدم CGI أو FPM. تأكد من أنك تقوم بتحرير php.ini "الصحيح". سيكون Apache الصحيح هو إذا كنت تقوم بتشغيل PHP مع Apache أو fpm أو php-fpm إذا كنت تستخدم PHP-FPM أو cgi إذا كنت تستخدم PHP-CGI ، إلخ. هذه ليست الطريقة الموصى بها ، ولكن إذا كنت لديك كود قديم سيكون من الصعب للغاية تعديله ، ثم قد يكون أفضل رهان لك.
قم بإيقاف تشغيل E_NOTICE
على مستوى الملف أو المجلد. قد يكون هذا هو الأفضل إذا كان لديك بعض الرموز القديمة ولكنك تريد أن تفعل الأشياء بالطريقة "الصحيحة" على خلاف ذلك. للقيام بذلك ، يجب عليك الرجوع إلى Apache2 أو Nginx أو أيًا كان الخادم الذي تختاره. في Apache ، يمكنك استخدام php_value
داخل <Directory>
.
أعد كتابة الكود لتكون أكثر نظافة إذا كنت بحاجة إلى القيام بذلك أثناء الانتقال إلى بيئة الإنتاج أو لا تريد أن يرى شخص ما أخطائك ، فتأكد من تعطيل أي عرض للأخطاء ، وفقط تسجيل / أخطائك (انظر display_errors
و log_errors
في php.ini وإعدادات الخادم الخاص بك).
للتوسع في الخيار 3: هذا هو المثالي. إذا كنت تستطيع أن تذهب في هذا الطريق ، يجب عليك. إذا لم تكن تسير في هذا الطريق في البداية ، ففكر في نقل هذا المسار في النهاية عن طريق اختبار الرمز في بيئة تطوير. أثناء تواجدك فيه ، تخلص من ~E_STRICT
و ~E_DEPRECATED
لمعرفة ما قد يحدث في المستقبل. سترى الكثير من الأخطاء غير المألوفة ، لكن ذلك سيمنعك من مواجهة أي مشاكل غير سارة عندما تحتاج إلى ترقية PHP في المستقبل.
Undefined variable: my_variable_name
- يحدث هذا عندما لا يتم تعريف متغير قبل الاستخدام. عندما يتم تنفيذ البرنامج النصي PHP ، فإنه داخليًا يفترض وجود قيمة خالية. ومع ذلك ، في أي سيناريو ستحتاج إلى التحقق من متغير قبل تحديده؟ في النهاية ، هذه حجة لـ "رمز قذر". كمطور ، يمكنني أن أخبرك أنني أحبها عندما أرى مشروعًا مفتوح المصدر حيث يتم تعريف المتغيرات على أنها عالية في نطاقاتها حيث يمكن تعريفها. يجعل الأمر أسهل في تحديد المتغيرات التي ستظهر في المستقبل ويجعل من الأسهل قراءة/معرفة الكود.
function foo()
{
$my_variable_name = '';
//....
if ($my_variable_name) {
// perform some logic
}
}
Undefined index: my_index
- يحدث هذا عند محاولة الوصول إلى قيمة في صفيف وهو غير موجود. لمنع هذا الخطأ ، قم بإجراء فحص مشروط.
// verbose way - generally better
if (isset($my_array['my_index'])) {
echo "My index value is: " . $my_array['my_index'];
}
// non-verbose ternary example - I use this sometimes for small rules.
$my_index_val = isset($my_array['my_index'])?$my_array['my_index']:'(undefined)';
echo "My index value is: " . $my_index_val;
خيار آخر هو إعلان مجموعة فارغة في الجزء العلوي من وظيفتك. ليس هذا ممكنا دائما.
$my_array = array(
'my_index' => ''
);
//...
$my_array['my_index'] = 'new string';
vim
هذه الأيام :).لماذا لا تبقي الأمور بسيطة؟
<?php
error_reporting(E_ALL); // making sure all notices are on
function idxVal(&$var, $default = null) {
return empty($var) ? $var = $default : $var;
}
echo idxVal($arr['test']); // returns null without any notice
echo idxVal($arr['hey ho'], 'yo'); // returns yo and assigns it to array index, Nice
?>
يعني الفهرس غير المحدد في صفيف طلبته لفهرس صفيف غير متوفر على سبيل المثال
<?php
$newArray[] = {1,2,3,4,5};
print_r($newArray[5]);
?>
متغير غير معرف يعني أنك استخدمت متغيراً غير موجود بالكامل أو لم يتم تعريفه أو تهيئته بهذا الاسم على سبيل المثال
<?php print_r($myvar); ?>
الإزاحة غير المحددة تعني في الصفيف أنك طلبت مفتاحًا غير موجود. والحل لهذا هو التحقق قبل الاستخدام
php> echo array_key_exists(1, $myarray);
فيما يتعلق بهذا الجزء من السؤال:
لماذا تظهر فجأة؟ اعتدت على استخدام هذا البرنامج النصي لسنوات ولم يسبق لي أن واجهت أي مشكلة.
لا توجد إجابات محددة ولكن فيما يلي بعض التفسيرات المحتملة لسبب تغيير الإعدادات "فجأة":
لقد قمت بالترقية PHP إلى إصدار أحدث يمكن أن يحتوي على إعدادات افتراضية أخرى للخطأ أو الإبلاغ عن الأخطاء أو الإعدادات الأخرى ذات الصلة.
لقد قمت بإزالة أو إدخال بعض الكود (ربما في تبعية) التي تحدد الإعدادات ذات الصلة في وقت التشغيل باستخدام ini_set()
أو error_reporting()
(ابحث عن هذه في الكود)
لقد قمت بتغيير تكوين خادم الويب (بافتراض Apache هنا): يمكن لملفات .htaccess
وتكوينات vhost أيضًا معالجة إعدادات php.
عادةً لا يتم عرض/الإبلاغ عن الإشعارات (راجع PHP دليل ) لذلك فمن الممكن عند إعداد الخادم ، تعذر تحميل ملف php.ini لسبب ما (أذونات الملف ؟؟) وكنت على الإعدادات الافتراضية. في وقت لاحق ، تم حل "الأخطاء" (عن طريق الصدفة) والآن يمكنه تحميل ملف php.ini الصحيح مع error_reporting لتعيين الإشعارات.
إذا كنت تعمل مع الفئات ، فأنت بحاجة إلى التأكد من الرجوع إلى متغيرات الأعضاء باستخدام $this
:
class Person
{
protected $firstName;
protected $lastName;
public function setFullName($first, $last)
{
// Correct
$this->firstName = $first;
// Incorrect
$lastName = $last;
// Incorrect
$this->$lastName = $last;
}
}
سبب آخر لإلغاء إشعار فهرس غير محدد ، هو حذف عمود من استعلام قاعدة البيانات.
أي.:
$query = "SELECT col1 FROM table WHERE col_x = ?";
ثم محاولة الوصول إلى المزيد من الأعمدة/الصفوف داخل حلقة.
أي.:
print_r($row['col1']);
print_r($row['col2']); // undefined index thrown
أو في حلقة while
:
while( $row = fetching_function($query) ) {
echo $row['col1'];
echo "<br>";
echo $row['col2']; // undefined index thrown
echo "<br>";
echo $row['col3']; // undefined index thrown
}
شيء آخر لا بد من الإشارة إليه هو أن الأمور حساسة لحالة الأحرف في نظام التشغيل * NIX OS و Mac OS X.
استشر الأسئلة والأجوبة التالية على المكدس:
استخدام ternary بسيط وقابل للقراءة ونظيف:
Pre PHP 7
عيّن متغيرًا إلى قيمة متغير آخر إذا تم تعيينه ، وإلا قم بتعيين null
(أو أيا كانت القيمة {الافتراضية) التي تحتاجها):
$newVariable = isset($thePotentialData) ? $thePotentialData : null;
PHP 7+
نفس الشيء باستثناء استخدام Null Coalescing Operator . لم تعد هناك حاجة للاتصال بـ isset()
نظرًا لأن هذا مضمّن ، وليس هناك حاجة لتوفير المتغير للعودة حيث يُفترض إرجاع قيمة المتغير الجاري فحصه:
$newVariable = $thePotentialData ?? null;
كلاهما سيوقف الإشعارات عن سؤال البروتوكول الاختياري ، و كلاهما تعادلان بالضبط:
if (isset($thePotentialData)) {
$newVariable = $thePotentialData;
} else {
$newVariable = null;
}
إذا كنت لا تحتاج إلى تعيين متغير جديد ، فيمكنك استخدام القيمة الثلاثية التي تم إرجاعها مباشرة ، مثل echo
، وسيطات الدوال ، إلخ:
الصدى:
echo 'Your name is: ' . isset($name) ? $name : 'You did not provide one';
الوظيفة:
$foreName = getForeName(isset($userId) ? $userId : null);
function getForeName($userId)
{
if ($userId === null) {
// Etc
}
}
ما سبق سوف يعمل بنفس الطريقة مع المصفوفات ، بما في ذلك الجلسات وما إلى ذلك ، لتحل محل المتغير الجاري فحصه على سبيل المثال:$_SESSION['checkMe']
أو مهما كانت مستويات كثيرة تحتاجها ، على سبيل المثال:$clients['personal']['address']['postcode']
قمع:
من الممكن منع PHP الإشعارات باستخدام @
أو تقليل مستوى الإبلاغ عن الخطأ ، ولكنه لا يحل المشكلة ، إنه ببساطة يتوقف عن الإبلاغ عنها في سجل الأخطاء. هذا يعني أن الشفرة ما زالت تحاول استخدام متغير لم يتم تعيينه ، والذي قد يعني أو لا يعني أن شيئًا ما لا يعمل كما هو مقصود - وهذا يتوقف على مدى أهمية القيمة المفقودة.
يجب أن تقوم بالفعل بالتحقق من هذه المشكلة والتعامل معها بشكل مناسب ، إما تقديم رسالة مختلفة ، أو حتى مجرد إرجاع قيمة فارغة لكل شيء آخر لتحديد الحالة الدقيقة.
إذا كنت تهتم فقط بعدم وجود إشعار في سجل الأخطاء ، فعندئذٍ كخيار يمكنك ببساطة تجاهل سجل الأخطاء.
لقد طرحت سؤالاً حول هذا الموضوع وتمت إحالتي إلى هذه المشاركة مع الرسالة:
هذا السؤال لديه بالفعل إجابة هنا:
"إشعار: متغير غير معرف" ، "إشعار: فهرس غير معرف" ، و "إشعار: تعويض غير معروف" باستخدام PHP
أشارك سؤالي وحلتي هنا:
هذا هو الخطأ:
السطر 154 هو المشكلة. هذا ما لدي في السطر 154:
153 foreach($cities as $key => $city){
154 if(($city != 'London') && ($city != 'Madrid') && ($citiesCounterArray[$key] >= 1)){
أعتقد أن المشكلة تكمن في أنني أكتب إذا كانت شروط المتغير $city
، وهي ليست المفتاح بل القيمة في $key => $city
. أولاً ، هل يمكنك تأكيد ما إذا كان هذا هو سبب التحذير؟ ثانياً ، إذا كانت هذه هي المشكلة ، فلماذا لا أستطيع كتابة شرط على أساس القيمة؟ هل يجب أن يكون مع المفتاح الذي أحتاجه لكتابة الشرط؟
التحديث 1: المشكلة هي أنه عند تنفيذ $citiesCounterArray[$key]
، في بعض الأحيان يتوافق $key
مع مفتاح غير موجود في صفيف $citiesCounterArray
، لكن هذا لا يحدث دائمًا بناءً على بيانات حلقي. ما أحتاجه هو تعيين شرط بحيث إذا كان $key
موجودًا في المصفوفة ، فقم بتشغيل الكود ، وإلا ، تخطيه.
تحديث 2: هذه هي الطريقة التي قمت بإصلاحها باستخدام array_key_exists()
:
foreach($cities as $key => $city){
if(array_key_exists($key, $citiesCounterArray)){
if(($city != 'London') && ($city != 'Madrid') && ($citiesCounterArray[$key] >= 1)){
أحد الأسباب الشائعة لمتغير غير موجود بعد إرسال نموذج HTML هو عدم تضمين عنصر النموذج ضمن علامة <form>
:
مثال: العنصر غير موجود في <form>
<form action="example.php" method="post">
<p>
<input type="text" name="name" />
<input type="submit" value="Submit" />
</p>
</form>
<select name="choice">
<option value="choice1">choice 1</option>
<option value="choice2">choice 2</option>
<option value="choice3">choice 3</option>
<option value="choice4">choice 4</option>
</select>
مثال: العنصر الموجود الآن ضمن <form>
<form action="example.php" method="post">
<select name="choice">
<option value="choice1">choice 1</option>
<option value="choice2">choice 2</option>
<option value="choice3">choice 3</option>
<option value="choice4">choice 4</option>
</select>
<p>
<input type="text" name="name" />
<input type="submit" value="Submit" />
</p>
</form>
عند التعامل مع الملفات ، يلزم وجود نمط مناسب وطريقة POST ، مما يؤدي إلى تشغيل إشعار فهرس غير محدد إذا لم يتم تضمين أي منهما في النموذج.
ينص الدليل على الصيغة الأساسية التالية:
HTML
<!-- The data encoding type, enctype, MUST be specified as below -->
<form enctype="multipart/form-data" action="__URL__" method="POST">
<!-- MAX_FILE_SIZE must precede the file input field -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- Name of input element determines name in $_FILES array -->
Send this file: <input name="userfile" type="file" />
<input type="submit" value="Send File" />
</form>
PHP
<?php
// In PHP versions earlier than 4.1.0, $HTTP_POST_FILES should be used instead
// of $_FILES.
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Possible file upload attack!\n";
}
echo 'Here is some more debugging info:';
print_r($_FILES);
print "</pre>";
?>
مرجع:
تحدث هذه الأخطاء عندما نستخدم متغيرًا لم يتم تعيينه.
أفضل طريقة للتعامل مع هذه هي إعداد تقرير عن الأخطاء أثناء التطوير.
لتعيين تقرير عن الخطأ في:
ini_set('error_reporting', 'on');
ini_set('display_errors', 'on');
error_reporting(E_ALL);
على خوادم الإنتاج ، يتم إيقاف الإبلاغ عن الأخطاء ، وبالتالي ، فإننا لا نحصل على هذه الأخطاء.
على خادم التطوير ، ومع ذلك ، يمكننا ضبط الإبلاغ عن الأخطاء على.
للتخلص من هذا الخطأ ، نرى المثال التالي:
if ($my == 9) {
$test = 'yes'; // Will produce error as $my is not 9.
}
echo $test;
يمكننا تهيئة المتغيرات إلى NULL
قبل تعيين قيمها أو استخدامها.
لذلك ، يمكننا تعديل الكود على النحو التالي:
$test = NULL;
if ($my == 9) {
$test = 'yes'; // Will produce error as $my is not 9.
}
echo $test;
لن يزعج هذا أي منطق في البرنامج ولن ينتج عنه إشعار حتى لو لم يكن هناك قيمة $test
.
لذلك ، في الأساس ، من الأفضل دائمًا تعيين الإبلاغ عن الخطأ للتطوير.
وإصلاح جميع الأخطاء.
وعلى الإنتاج ، يجب ضبط الإبلاغ عن الأخطاء.
ربما كنت تستخدم الإصدار PHP القديم حتى الآن وقمت بالترقية PHP وهذا هو السبب في أنه كان يعمل دون أي خطأ حتى الآن منذ سنوات. حتى PHP4 ، لم يكن هناك أي خطأ إذا كنت تستخدم المتغير دون تعريفه ولكن اعتبارًا من PHP5 فصاعدًا ، فإنه يلقي أخطاء على أكواد مثل المذكورة في السؤال.