اذهب إلى المحتوى

معالجة خيارات البرنامج

يمكن معالجة خيارات البرنامج باستخدام الدالة getopt()‎، التي تعمل بصيغة مشابهة للأمر getopt في معايير POSIX مع دعم إضافي للخيارات الطويلة ذات النمط GNU.

#!/usr/bin/php

// تشير النقطتين إلى خيار يأخذ قيمة
// تشير النقطتين المضاعفتين إلى قيمة يمكن إهمالها
$shortopts = "hf:v::d";

// ‫الخيارات الطويلة ذات النمط GNU غير مطلوبة
$longopts = ["help", "version"];
$opts = getopt($shortopts, $longopts);

// ‫تُسند القيمة المنطقية false للخيارات التي ليس لها قيم، يجب التحقق من وجودها وليس صدقها
if (isset($opts["h"]) || isset($opts["help"])) {
    fprintf(STDERR, "Here is some help!\n");
    exit;
}

// ‫تُستدعى الخيارات الطويلة مع شرطتين: "‎--version"
if (isset($opts["version"])) {
    fprintf(STDERR, "%s Version 223.45" . PHP_EOL, $argv[0]);
exit;
}

// ‫يمكن استدعاء الخيارات ذات القيم بالشكل "‎-f foo" أو ‏"‎-ffoo" أو "‎-f=foo"
$file = "";
if (isset($opts["f"])) {
    $file = $opts["f"];
}
if (empty($file)) {
    fprintf(STDERR, "We wanted a file!" . PHP_EOL);
    exit(1);
}
fprintf(STDOUT, "File is %s" . PHP_EOL, $file);

// ‫يمكن استدعاء الخيارات ذات القيم الافتراضية بالشكل "‎-v5" أو "‎-v=5"
$verbosity = 0;
if (isset($opts["v"])) {
    $verbosity = ($opts["v"] === false) ? 1 : (int)$opts["v"];
}
fprintf(STDOUT, "Verbosity is %d" . PHP_EOL, $verbosity);

// تُمرَّر الخيارات التي نستدعيها عدة مرات كمصفوفة
$debug = 0;
if (isset($opts["d"])) {
    $debug = is_array($opts["d"]) ? count($opts["d"]) : 1;
}
fprintf(STDOUT, "Debug is %d" . PHP_EOL, $debug);

// ‫لا توجد طريقة تلقائية عند getopt لمعالجة الخيارات غير المتوقعة

يمكن اختبار السكربت السابق بالشكل:

./test.php --help
./test.php --version
./test.php -f foo -ddd
./test.php -v -d -ffoo
./test.php -v5 -f=foo
./test.php -f foo -v 5 -d

لاحظ أنّ الطريقة الأخيرة لن تعمل لأنّ ‎-v 5 غير صحيحة.

ملاحظة: يعدّ الأمر getopt بدءًا من الإصدار PHP 5.3.0 مستقلًا عن نظام التشغيل ويعمل أيضًا على نظام ويندوز.

معالجة الوسيط

تُمرَّر الوسائط إلى البرنامج بطريقة مشابهة لمعظم اللغات ذات النمط C، إنّ ‎$argc عدد صحيح يعبّر عن عدد الوسائط متضمنةً اسم البرنامج و‎$argv مصفوفة تتضمن وسائط البرنامج. العنصر الأول من ‎$argv هو اسم البرنامج.

#!/usr/bin/php
printf("You called the program %s with %d arguments\n", $argv[0], $argc - 1);
unset($argv[0]);
foreach ($argv as $i => $arg) {
    printf("Argument %d is %s\n", $i, $arg);
}

استدعاء التطبيق السابق باستخدام php example.php foo bar (حيث يتضمن الملف example.php الشيفرة السابقة) سيؤدي إلى الخرج التالي:

You called the program example.php with 2 arguments
Argument 1 is foo
Argument 2 is bar

لاحظ أنّ ‎$argc و‎$argv هي متغيرات عامة وليست متغيرات ذات نطاق عام عالي، ويجب استيرادها إلى النطاق المحلي باستخدام الكلمة المفتاحية global عندما نحتاج إلى استخدامها في دالة ما.

يُظهر هذا المثال كيف تُجمَّع الوسائط عندما نهرب باستخدام "" أو \.

مثال عن سكربت:

var_dump($argc, $argv);

سطر الأوامر:

$ php argc.argv.php --this-is-an-option three\ words\ together or "in one quote" but\ multiple\spaces\ counted\ as\ one
int(6)
array(6) {
    [0]=>
    string(13) "argc.argv.php"
    [1]=>
    string(19) "--this-is-an-option"
    [2]=>
    string(20) "three words together"
    [3]=>
    string(2) "or"
    [4]=>
    string(12) "in one quote"
    [5]=>
    string(34) "but multiple spaces counted as one"
}

إذا نُفِّذ سكربت PHP باستخدام ‎-r:

$ php -r 'var_dump($argv);'
array(1) {
    [0]=>
    string(1) "-"
}

أو تُرسل الشيفرة عبر أنبوب في مجرى الدخل القياسي php:

$ echo '<?php var_dump($argv);' | php
array(1) {
    [0]=>
    string(1) "-"
}

معالجة الدخل والخرج

إنّ الثوابت STDIN وSTDOUT وSTDERR معرَّفة مسبقًا عند التنفيذ من واجهة سطر الأوامر (CLI)، وهي مقابض للملف يمكن أن نعدّها مكافئة لنتائج تنفيذ الأوامر التالية:

STDIN = fopen("php://stdin", "r");
STDOUT = fopen("php://stdout", "w");
STDERR = fopen("php://stderr", "w");

يمكن استخدام الثوابت في أي مكان يكون مقبض الملف القياسي فيه:

#!/usr/bin/php

while ($line = fgets(STDIN)) {
    $line = strtolower(trim($line));
    switch ($line) {
        case "bad":
        fprintf(STDERR, "%s is bad" . PHP_EOL, $line);
        break;
        case "quit":
        exit;
        default:
        fprintf(STDOUT, "%s is good" . PHP_EOL, $line);
        break;
    }
}

يمكن استخدام عناوين المجرى المضمَّن المُشار إليها سابقًا php://stdin وphp://stdout وphp://stderr مكان أسماء الملفات في معظم الحالات:

file_put_contents('php://stdout', 'This is stdout content');
file_put_contents('php://stderr', 'This is stderr content');

// فتح المقبض والكتابة عدة مرات
$stdout = fopen('php://stdout', 'w');
fwrite($stdout, 'Hello world from stdout' . PHP_EOL);
fwrite($stdout, 'Hello again');

fclose($stdout);

يمكن أن تستخدم أيضًا الدالة readline()‎ كبديل للدخل وتستخدم echo أو print أو أي دالة من دوال طباعة السلسلة النصية كبديل للخرج.

$name = readline("Please enter your name:");
print "Hello, {$name}.";

الشيفرات المُعادة

يمكن استخدام البنية exit لتمرير شيفرة معادة إلى بيئة التنفيذ.

#!/usr/bin/php
if ($argv[1] === "bad") {
    exit(1);
} else {
    exit(0);
}

ستُرجَع شيفرة الخروج 0 بشكلٍ افتراضي إذا لم تُمرَّر قيمة أي أنّ exit نفس exit(0)‎ وبما أنّ exit ليست دالة فإنّ الأقواس غير ضرورية إذا لم تُمرَّر شيفرة معادة.

يجب أن تكون الشيفرات المُعادة في المجال بين 0 و254 (الشيفرة 255 محجوزة من قِبَل PHP ويجب عدم استخدامها)، اصطلاحًا إنّ الخروج بالشيفرة المُرجعة 0 تُخبر البرنامج المُستدعي أنّ سكربت PHP نُفِّذ بنجاح أما الشيفرة المرجعية غير الصفرية تُخبر البرنامج المستدعي بحدوث حالة خطأ محددة.

قصر تنفيذ السكربت على سطر الأوامر

يُرجع كل من الدالة php_sapi_name()‎ والثابت PHP_SAPI نوع الواجهة (واجهة برمجة تطبيقات الخادم Server API) التي تستخدمها PHP، ويمكن استخدامها لقصر تنفيذ السكربت على سطر الأوامر عن طريق التحقق فيما إذا كان خرج الدالة يساوي cli.

if (php_sapi_name() === 'cli') {
    echo "Executed from command line\n";
} else {
    echo "Executed from web browser\n";
}

الدالة drupal_is_cli()‎ هي مثال عن دالة تكتشف فيما إذا كان السكربت قد نُفِّذ من سطر الأوامر:

function drupal_is_cli() {
    return (!isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
}

الاختلافات السلوكية في سطر الأوامر

تعرض PHP عند التنفيذ من CLI بعض السلوكيات المختلفة عن السلوكيات عند التنفيذ على خادم ويب، يجب أن تتذكر هذه السلوكيات خاصةً في حالة تنفيذ نفس السكربت في البيئتين.

  • لا يتغير المجلد عند التنفيذ على خادم ويب بل يبقى مجلد العمل الحالي للسكربت نفسه دائمًا، تفترض الشيفرة require("./stuff.inc");‎ أنّ الملف في نفس مجلد السكربت، أما في سطر الأوامر فإنّ مجلد العمل الحالي هو المجلد الذي يُستدعى منه السكربت، يجب أن تستخدم السكربتات التي ستُستدعى من سطر الأوامر مسارات مطلقة. (لاحظ أنّ الثوابت السحرية __DIR__ و__FILE__ تبقى تعمل كما هو متوقع وتُرجع موقع السكربت).
  • لا يوجد مخزن مؤقت للخرج، القيم الافتراضية لموجهات الملف php.ini ‏output_buffering وimplicit_flush هي false وtrue على الترتيب. ويبقى المخزن المؤقت متوفرًا لكن يجب تمكينه بشكلٍ صريح وإلا سيُعرض الخرج دائمًا في الوقت الحقيقي.
  • لا يوجد قيد زمني، يُضبط الموجه max_execution_time في الملف php.ini إلى القيمة صفر لذا لن ينتهي وقت تنفيذ السكربتات بشكلٍ افتراضي.
  • لا توجد أخطاء HTML، إذا مكّنت الموجّه html_errors في ملف php.ini سيتجاهله سطر الأوامر.
  • يمكن تحميل ملفات php.ini مختلفة، إذا كنت تستخدم PHP من CLI يمكنك تحميل ملفات php.ini مختلفة وهذا غير متاح عند التنفيذ على خادم ويب، يمكنك أن تعرف ما هو الملف المستخدم بتنفيذ الأمر php ‎--ini‎.

تنفيذ السكربت

في كل من لينوكس/يونكس أو ويندوز يمكن تمرير الملف كوسيط إلى PHP القابلة للتنفيذ مع خيارات ووسائط السكربت:

php ~/example.php foo bar

c:\php\php.exe c:\example.php foo bar

تمرر الشيفرة السابقة الوسائط foo وbar إلى الملف example.php.

الطريقة المفضلة لتنفيذ السكربتات في لينوكس/يونكس هي استخدام Shebang (سطر يبدأ بالسلسلة النصية "‎ #! ‎") مثل ‎#!/usr/bin/env php في السطر الأول من الملف وضبط البت القابل للتنفيذ على الملف، بفرض أنّ السكربت في مسارك يمكنك عندها استدعاؤه مباشرةً:

example.php foo bar

إنّ استخدام ‎/usr/bin/env php‎ يجعل من الممكن العثور على PHP القابلة للتنفيذ باستخدام PATH. وفقًا لكيفية تثبيت PHP قد لا تكون موجودة في نفس المكان (مثل ‎/usr/bin/php‎ أو ‎/usr/local/bin/php) على عكس env المتوفرة عادةً في ‎/usr/bin/env.

في ويندوز قد تحصل على نفس النتيجة بإضافة مجلد PHP والسكربت الخاص بك إلى PATH وتعديل PATHEXT ليسمح باكتشاف ‎.php باستخدام PATH، الاحتمال الآخر هو إضافة ملف باسم example.bat أو example.cmd في نفس المجلد الموجود به سكربت PHP وكتابة هذا السطر فيه:

c:\php\php.exe "%~dp0example.php" %*

أو إذا أضفت مجلد PHP داخل PATH:

php "%~dp0example.php" %*

حالات متقدمة لاستخدام getopt()‎

يظهر هذا المثال سلوك getopt عندما يكون دخل المستخدم غير شائع، محتويات الملف getopt.php:

var_dump(
    getopt("ab:c::", ["delta", "epsilon:", "zeta::"])
);

سطر أوامر الصدفة:

$ php getopt.php -a -a -bbeta -b beta -cgamma --delta --epsilon --zeta --zeta=f -c gamma
array(6) {
    ["a"]=>
    array(2) {
        [0]=>
        bool(false)
        [1]=>
        bool(false)
    }
    ["b"]=>
    array(2) {
        [0]=>
        string(4) "beta"
        [1]=>
        string(4) "beta"
    }
    ["c"]=>
    array(2) {
        [0]=>
        string(5) "gamma"
        [1]=>
        bool(false)
    }
    ["delta"]=>
        bool(false)
    ["epsilon"]=>
        string(6) "--zeta"
    ["zeta"]=>
        string(1) "f"
}

يمكننا أن نلاحظ من المثال السابق:

  • تحمل الخيارات الفردية (بدون نقطتان) دائمًا القيمة المنطقية false إذا مُكِّنت.
  • إذا كُرِّر خيار ما فإنّ قيمة خرج getopt ستصبح مصفوفة.
  • تقبل خيارات الوسيط المطلوب (بنقطتين) فراغ واحد أو عدم وجود فراغ (مثل خيارات الوسيط الاختيارية) كفاصل.
  • بعد وجود وسيط واحد لا يمكن ربطه بأي خيار فإنّ الخيارات التالية لن تُربط أيضًا.

تشغيل خادم ويب مدمج

أصبحت PHP بدءًا من الإصدار PHP 5.4 تأتي مع خادم مدمج، يمكن استخدامه لتنفيذ تطبيق بدون الحاجة لتثبيت أي خادم http مثل nginx أو apache، صُمم الخادم المدمج في بيئة المتحكم فقط لأهداف التطوير والاختبار، يمكن تنفيذه باستخدام الأمر php -S ولاختباره ننشئ الملف index.php ونكتب فيه:

<?php
echo "Hello World from built-in PHP server";

وننفذ الأمر:

php -S localhost:8080

يجب أن تكون الآن قادرًا على رؤية المحتوى في المتصفح، للتحقق من ذلك انتقل إلى المسار http://localhost:8080 ، ويجب أن يؤدي كل وصول إلى مدخل سجل يُكتب في الطرفية (Terminal).

[Mon Aug 15 18:20:19 2016] ::1:52455 [200]: /

ترجمة -وبتصرف- للفصل [Command Line Interface (CLI)‎] من كتاب PHP Notes for Professionals book

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

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

×   جرى استعادة المحتوى السابق..   امسح المحرر

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


×
×
  • أضف...