Nette Command-Line
PHP'de komut satırı uygulamaları kurmak için hafif bir kütüphane. Anahtarları, seçenekleri ve konumsal argümanları ayrıştırır ve ANSI desteğiyle renkli terminal çıktısı üretmenize yardım eder.
Kurulum:
composer require nette/command-line
PHP 8.2 sürümünü gerektirir ve PHP 8.5'e dek destekler.
Komut Satırı Argümanlarını Ayrıştırma
Her CLI betiğinin --verbose, -o output.txt ya da düz dosya adları gibi argümanları ele alması
gerekir. Nette\CommandLine\Parser sınıfı
başlamanın en hızlı yolunu sunar: yardım metninizi yazın ve ayrıştırıcının seçenek tanımlarını ondan
çıkarmasına izin verin:
use Nette\CommandLine\Parser;
$parser = new Parser;
$parser->addFromHelp('
-h, --help Show this help
-v, --verbose Enable verbose mode
-o, --output <file> Output file
-f, --format [type] Output format (default: json)
-I, --include <path>... Include paths
--dry-run Show what would be done
');
$args = $parser->parse();
Hepsi bu. Ayrıştırıcı, --verbose seçeneğinin bir anahtar olduğunu, --output seçeneğinin bir
değer gerektirdiğini ve --format seçeneğinin json yedekli isteğe bağlı bir değeri olduğunu
anlar. Yardım metniniz gerçek seçenek tanımlarıyla eşzamanlı kalır.
parse() metodu ilişkisel bir dizi döndürür. Anahtarlar, tirelerle birlikte, tanımlandıkları gibi seçenek
adlarıyla tam olarak eşleşir:
[
'--help' => true, // ya da kullanılmadıysa null
'--verbose' => null,
'--output' => 'file.txt', // ya da kullanılmadıysa null
'--format' => 'json', // (default: json) yedeği
'--include' => ['src', 'lib'],
'--dry-run' => null,
]
parse() varsayılan olarak $_SERVER['argv'] içinden okur. Sınamalarda kullanışlı olan özel bir
dizi aktarabilirsiniz:
$args = $parser->parse(['--verbose', '-o', 'out.txt']);
Yardım Metni Sözdizimi
Ayrıştırıcı, biçimlendirilmiş yardım metninden seçenek tanımlarını şu kurallara göre çıkarır:
--verbose |
Anahtar (değersiz) |
-v, --verbose |
Kısa alias'lı anahtar |
--output <file> |
Zorunlu değerli seçenek |
--format [type] |
İsteğe bağlı değerli seçenek |
(default: json) |
Yedek değeri belirler |
<path>... |
Yinelenebilir seçenek |
Her satır bir seçenek tanımlar. Seçenek adları, açıklamalarından en az iki boşlukla ayrılmalıdır.
Ek Yapılandırma
Bazı ayarlar yardım metninde ifade edilemez. İkinci parametre olarak, seçenek adına göre anahtarlanmış bir dizi aktarın:
$parser->addFromHelp('
-c, --config <file> Configuration file
-I, --include <path> Include path
-n, --count <num> Number of iterations
', [
'--config' => [
Parser::RealPath => true,
],
'--include' => [
Parser::Repeatable => true,
],
'--count' => [
Parser::Normalizer => fn($v) => (int) $v,
],
]);
Kullanılabilir anahtarlar:
Parser::Repeatable |
Birden çok değeri bir dizide toplar |
Parser::RealPath |
Dosyanın var olduğunu doğrular ve onu mutlak yola çözer |
Parser::Normalizer |
Dönüştürme fonksiyonu fn($value) => ... |
Parser::Default |
Yedek değer (yardım metnindeki (default: x) ile aynı) |
Parser::Enum |
İzin verilen değerlerden oluşan dizi |
Akıcı API
Seçenek tanımları üzerinde daha fazla denetime gereksinim duyduğunuzda, addSwitch(), addOption()
ve addArgument() metotlarıyla akıcı API'yi kullanın. Bu yaklaşım; normalizer'lar, enum'lar ve her parametre
üzerinde kesin denetim dahil tüm özelliklere erişim verir:
use Nette\CommandLine\Parser;
$parser = new Parser;
$parser
->addSwitch('--verbose', '-v')
->addOption('--output', '-o')
->addArgument('file');
$args = $parser->parse();
addFromHelp() metodunda olduğu gibi, sınama için parse() metoduna özel bir dizi
aktarabilirsiniz:
$args = $parser->parse(['--verbose', '-o', 'out.txt', 'input.txt']);
Anahtarlar, Seçenekler ve Argümanlar
Üç tip komut satırı girdisi vardır:
Anahtarlar, --verbose ya da -v gibi değersiz bayraklardır. Bulunduklarında
true, bulunmadıklarında null olarak ayrıştırılırlar:
$parser->addSwitch('--verbose', '-v');
// --verbose → true
// -v → true
// (kullanılmadı) → null
Seçenekler, --output file.txt gibi değer kabul eder. Değer bir boşlukla ya da = ile
ayrılabilir:
$parser->addOption('--output', '-o');
// --output file.txt → 'file.txt'
// --output=file.txt → 'file.txt'
// -o file.txt → 'file.txt'
// --output → istisna fırlatır (değer gerekli)
// (kullanılmadı) → null
Seçeneğin kendisinin her zaman isteğe bağlı olduğuna dikkat edin; onu kullanmamak null döndürür. Ancak
kullanıldığında değer varsayılan olarak zorunludur. Seçeneğe değersiz izin vermek için optionalValue: true
ayarlayın (o zaman true olarak ayrıştırılır):
$parser->addOption('--format', '-f', optionalValue: true);
// --format json → 'json'
// --format → true
// (kullanılmadı) → null
Aynı seçenek repeatable: true olmadan birden çok kez kullanıldığında son değer kazanır:
$parser->addOption('--output', '-o');
// -o first.txt -o second.txt → 'second.txt'
Argümanlar, tiresiz konumsal değerlerdir. Varsayılan olarak zorunludurlar. Onları isteğe bağlı kılmak için
optional: true ayarlayın:
$parser->addArgument('input');
// script.php file.txt → 'file.txt'
// (kullanılmadı) → istisna fırlatır
$parser->addArgument('output', optional: true);
// (kullanılmadı) → null
$parser->addArgument('output', optional: true, fallback: 'out.txt');
// (kullanılmadı) → 'out.txt'
İsteğe bağlı bir seçenek ya da argüman verilmediğinde kullanılacak değeri belirtmek için fallback
kullanın. optionalValue: true olan seçeneklerde, seçeneği değersiz kullanmanın yine true olarak
ayrıştırıldığını, yedeğin ise yalnızca seçenek hiç bulunmadığında kullanıldığını unutmayın:
$parser->addOption('--format', '-f', optionalValue: true, fallback: 'json');
// --format xml → 'xml'
// --format → true (seçenek değersiz kullanıldı)
// (kullanılmadı) → 'json' (yedek)
Argümanlar komut satırının herhangi bir yerinde bulunabilir; seçeneklerden sonra gelmeleri gerekmez:
// bunların hepsi eşdeğerdir:
// script.php --verbose input.txt
// script.php input.txt --verbose
Değerleri Enum ile Kısıtlama
Kabul edilen değerleri belirli bir kümeyle sınırlayın:
$parser->addOption('--format', '-f', enum: ['json', 'xml', 'csv']);
// --format yaml → "Value of option --format must be json, or xml, or csv." fırlatır
Yinelenebilir Seçenekler
Birden çok değeri bir dizide toplamak için repeatable: true ayarlayın:
$parser->addOption('--include', '-I', repeatable: true);
// -I src -I lib → ['src', 'lib']
// (kullanılmadı) → []
$parser->addArgument('files', optional: true, repeatable: true);
// a.txt b.txt → ['a.txt', 'b.txt']
Değerleri Dönüştürme
Ayrıştırılan değeri dönüştürmek için bir normalizer kullanın:
$parser->addOption('--count', normalizer: fn($v) => (int) $v);
// --count 42 → 42 (tam sayı)
Dosya yolu doğrulaması için yerleşik normalizeRealPath kullanın:
$parser->addOption('--config', normalizer: Parser::normalizeRealPath(...));
// --config app.ini → '/full/path/to/app.ini'
// --config missing.ini → "File path 'missing.ini' not found." fırlatır
İki Yaklaşımı Karıştırma
Normalizer'lara yalnızca bazı seçenekler için gereksinim duyduğunuzda addFromHelp() metodunu akıcı
metotlarla birleştirebilirsiniz:
$parser
->addFromHelp('
-v, --verbose Enable verbose mode
-q, --quiet Suppress output
')
->addOption('--config', '-c', normalizer: Parser::normalizeRealPath(...))
->addArgument('input');
Hata Ele Alma
Ayrıştırıcı geçersiz girdi için \Exception fırlatır:
use Nette\CommandLine\Parser;
$parser = new Parser;
$parser
->addOption('--output', '-o')
->addArgument('file');
try {
$args = $parser->parse();
} catch (\Exception $e) {
fwrite(STDERR, "Error: {$e->getMessage()}\n");
exit(1);
}
Yaygın hata mesajları:
Option --output requires argument. |
Seçenek, zorunlu değeri olmadan kullanıldı |
Unknown option --foo. |
Tanınmayan seçenek |
Missing required argument <file>. |
Zorunlu argüman verilmedi |
Unexpected parameter foo. |
Fazladan konumsal argüman |
Value of option --format must be json, or xml. |
Değer enum'da yok |
Hiç komut satırı argümanı verilmediğini (yani kullanıcının ardında hiçbir şey olmadan yalnızca
script.php çalıştırdığını) denetlemek için isEmpty() kullanın:
if ($parser->isEmpty()) {
$parser->help();
exit;
}
--help ve –version Ele Alma
Betiğinizin zorunlu argümanları varsa, script.php --help çalıştırmak normalde zorunlu argüman eksik
olduğu için başarısız olurdu. Önce bilgi seçeneklerini denetlemek için parseOnly() kullanın:
$parser = new Parser;
$parser
->addSwitch('--help', '-h')
->addSwitch('--version', '-V')
->addArgument('input'); // zorunlu
// Önce bilgi seçeneklerini denetle (doğrulama yok, istisna yok)
$info = $parser->parseOnly(['--help', '--version']);
if ($info['--help']) {
$parser->help();
exit;
}
if ($info['--version']) {
echo "1.0.0\n";
exit;
}
// Şimdi doğrulamayla tam ayrıştırmayı yap
$args = $parser->parse();
parseOnly() metodu:
- yalnızca belirtilen seçenekleri ayrıştırır, geri kalan her şeyi yok sayar,
- alias'lara saygı gösterir (
-h→--help), - asla istisna fırlatmaz,
- kullanılmayan seçenekler için
nulldöndürür.
Renkli Çıktı
Nette\CommandLine\Console sınıfı, çıktınızın terminalde öne çıkması için metni ANSI renk kodlarıyla sarar:
use Nette\CommandLine\Console;
$console = new Console;
echo $console->color('red', 'Error!') . "\n";
echo $console->color('white/blue', 'White text on blue background') . "\n";
Renk 'ön plan' ya da 'ön plan/arka plan' olarak verilir. Kullanılabilir renkler şunlardır:
black, gray, silver, white, navy, blue,
green, lime, teal, aqua, maroon, red,
purple, fuchsia, olive ve yellow.
Renkler yalnızca çıktı onları desteklediğinde otomatik etkinleşir. color() metodu, renkler kapalıyken düz
bir dize döndürür, dolayısıyla onu çağırmak her zaman güvenlidir. Davranışı elle zorlayabilirsiniz:
$console->useColors(false); // renkleri kapat
$console->useColors(true); // renkleri zorla aç
Terminali Algılama
İki statik metot, yalnızca terminale özgü özellikleri kullanıp kullanmayacağınıza karar vermenize yardım eder.
detectColors(), NO_COLOR ortam değişkeni ayarlıysa ya da çıktı bir CLI
terminali değilse false döndürür; FORCE_COLOR değişkeni terminal denetimini geçersiz kılar:
if (Console::detectColors()) {
// terminal ANSI renklerini destekliyor
}
detectTerminal(), çıktının etkileşimli bir terminal (bir TTY) olup olmadığını söyler. Bu; ilerleme
göstergeleri, satır yeniden yazan çıktı ya da etkileşimli sorular gibi yalnızca terminalde anlamlı olan özellikleri
otomatik kapatmak için yararlıdır:
if (Console::detectTerminal()) {
// çıktı bir dosyaya ya da boruya değil, etkileşimli bir terminale gidiyor
}
Eksiksiz Örnek
İşte Parser ile Console sınıflarını birleştiren, gerçek dünyadan bir dosya dönüştürme
betiği:
#!/usr/bin/env php
<?php
use Nette\CommandLine\Parser;
require __DIR__ . '/vendor/autoload.php';
$parser = new Parser;
$parser
->addFromHelp('
-h, --help Show this help
-v, --verbose Show detailed output
-n, --dry-run Show what would be done
-f, --format [type] Output format (default: json)
-o, --output <file> Output file
', [
'--format' => [
Parser::Enum => ['json', 'xml', 'csv'],
],
])
->addArgument('input', normalizer: Parser::normalizeRealPath(...));
// --help seçeneğini doğrulamadan önce ele al ("eksik argüman" hatasından kaçınır)
if ($parser->isEmpty() || $parser->parseOnly(['--help'])['--help']) {
echo "Usage: convert [options] <input>\n\n";
$parser->help();
exit;
}
try {
$args = $parser->parse();
} catch (\Exception $e) {
fwrite(STDERR, "Error: {$e->getMessage()}\n");
exit(1);
}
if ($args['--verbose']) {
echo "Converting {$args['input']} to {$args['--format']}...\n";
}
if ($args['--dry-run']) {
echo "Dry run: no changes made.\n";
exit;
}
// ... dönüştürme mantığı burada ...
echo "Done!\n";
Betik şu gibi komutları kabul eder:
convert input.txt– varsayılanlarla dönüştürconvert -v --format xml input.txt– ayrıntılı, XML biçimiconvert -o result.txt input.txt– çıktı dosyasını belirtconvert --help– yardımı göster (girdi dosyası olmadan bile çalışır)