İçeriğe geç
academia.sh

Ders 03 / 15

Yapılandırma ve Ortam Değişkenleri

Bağlantı adı ve anahtar gibi dağıtıma bağlı değerleri koddan ayırıp ortam değişkenlerinden okumak; eksik değişkende açık hata ve kodda sabit yazılan değerin bedeli.

Yayın Güncelleme

Bu derste

  • Dağıtıma bağlı değerleri koda yazmak yerine ortam değişkeninden okuyan bir yapılandırma kurar
  • Varsayılan değeri ve eksik değişkende açık hatayı ayırt eder
  • Aynı kodun ortam değişince farklı sonuç verdiğini ölçüp sonucu ortam olarak sınıflar
  • Kodda sabit yazılan değerin ortamın sapmasına dayandığını ve bedelini okur
İçindekiler

Çerezler dersinde sepet istemcide, Oturumlar dersinde sunucuda durdu. İkisinde de değeri belirleyen istekti. Bir uygulamanın okuduğu her değer istekten gelmez: hangi veritabanına bağlanacağı, imza anahtarı, bir dış servisin adresi uygulama dağıtılırken belirlenir. Aynı kod geliştiricinin makinesinde bir değerle, üretimde başka bir değerle koşar.

Bu değerleri taşıyan en yaygın yol ortam değişkenidir (environment variable): işletim sisteminin bir sürece verdiği ad ve değer çiftleri. PHP’de getenv() okur, putenv() yazar. Dağıtımı yapan kişi ya da araç değişkeni süreç başlamadan önce kurar; uygulama kodu onu normalde yalnız okur. Üretim Go: Test, Araçlar ve Başarım kursunda sorulan soru bir bilginin hangi araçtan okunduğuydu. Burada soru, değeri kimin değiştirebildiğidir.

Yapılandırma Katmanı

Ortamdan okuma kodun her yerine dağıtılmaz; tek bir yerde toplanır. yapilandirma.php üç fonksiyon verir ve ölçümün de dayanağı budur.

<?php
// yapilandirma.php — ortam değişkenlerinden yapılandırma okuyan yardımcılar
declare(strict_types=1);

function ortam(string $ad, ?string $varsayilan = null): string
{
    $deger = getenv($ad);
    if ($deger !== false) {
        return $deger;
    }
    if ($varsayilan !== null) {
        return $varsayilan;
    }
    throw new RuntimeException("eksik ortam değişkeni: $ad");
}

function yapilandirma(): array
{
    return [
        'veritabani' => ortam('UYG_VERITABANI', 'uygulama.db'),
        'anahtar' => ortam('UYG_ANAHTAR'),
    ];
}

/** Değişkenleri geçici olarak kurar, işi yapar, eski değerleri geri koyar. */
function ortamla(array $degiskenler, callable $is): mixed
{
    $eskiler = [];
    foreach ($degiskenler as $ad => $deger) {
        $eskiler[$ad] = getenv($ad);
        putenv("$ad=$deger");
    }
    try {
        return $is();
    } finally {
        foreach ($eskiler as $ad => $eski) {
            putenv($eski === false ? $ad : "$ad=$eski");
        }
    }
}

ortam() değişkeni getenv() ile okur. Değişken yoksa getenv() false döner; fonksiyon önce varsayılan değere bakar, o da verilmediyse RuntimeException fırlatır. Varsayılan ile hata arasındaki ayrım bilinçlidir: veritabanı adı için makul bir varsayılan vardır, anahtar için yoktur. Anahtar eksikse sessizce boş bir değerle ilerlemek, imzasız bir uygulamayı yayına almak olurdu; uygulama açılırken durmalıdır.

yapilandirma() değerleri bir dizide toplar. Kodun geri kalanı getenv() bilmez, bu diziyi ister. ortamla() ölçüm yardımcısıdır: değişkenleri geçici kurar, işi yapar ve eski değerleri geri koyar.

Taraf çekirdeği bu derste de aynıdır ve değişmez.

<?php
// taraf.php — bu sonucu kim değiştirebiliyor?
declare(strict_types=1);

// Kodun dışındaki taraflar, karar sırasıyla: her istek, her dış çağrı, her dağıtım.
const DIS_TARAFLAR = ['istemci', 'üçüncü taraf', 'ortam'];

/** Sonucu bir kez sapmasız, sonra her dış tarafın sapmasıyla ayrı ayrı hesaplar. */
function sina(callable $sonuc, array $sapmalar): array {
    $taban = $sonuc([]);
    $degisti = [];
    foreach (DIS_TARAFLAR as $taraf) {
        if (array_key_exists($taraf, $sapmalar)) {
            $degisti[$taraf] = $sonuc([$taraf => $sapmalar[$taraf]]) !== $taban;
        }
    }
    return $degisti;
}

/** Sonucu değiştirebilen ilk dış taraf; hiçbiri değiştiremiyorsa sunucu. */
function taraf(array $degisti): string {
    foreach (DIS_TARAFLAR as $t) {
        if ($degisti[$t] ?? false) return $t;
    }
    return 'sunucu';
}

function tarafRaporu(string $ad, callable $sonuc, array $sapmalar): string {
    $degisti = sina($sonuc, $sapmalar);
    $satirlar = [];
    foreach ($degisti as $t => $d) $satirlar[] = $t . ($d ? ' değiştirdi' : ' değiştiremedi');
    $sonTaraf = taraf($degisti);
    echo "$ad → $sonTaraf\n    ", implode(' · ', $satirlar), "\n";
    return $sonTaraf;
}

Aynı Kod, Farklı Ortam

ortam.php önce iki değişkeni siler, böylece ders çalışma ortamının ne taşıdığına güvenmez. Sonra eksik anahtarla yapilandirma() çağırır ve hatayı yakalar. Hata sınıfının adı ve iletisi basılır; iletiyi bu kod yazdığı için ortamdan bağımsızdır. Sonra anahtarı kurar ve okundu bilgisini basar. Anahtarın kendisi basılmaz: gizli değer günlüğe, çıktıya ya da hata iletisine girmez.

<?php
// ortam.php — aynı kod, farklı ortam, farklı bağlantı adı
declare(strict_types=1);

require 'taraf.php';
require 'yapilandirma.php';

putenv('UYG_VERITABANI');
putenv('UYG_ANAHTAR');

try {
    yapilandirma();
} catch (RuntimeException $hata) {
    echo get_class($hata), ': ', $hata->getMessage(), "\n";
}

putenv('UYG_ANAHTAR=ders-gizli-deger');
$ayar = yapilandirma();
echo 'anahtar okundu: ', $ayar['anahtar'] !== '' ? 'evet' : 'hayır', "\n";

tarafRaporu(
    'veritabanı adı (ortam değişkeninden)',
    fn(array $s) => ortamla($s['ortam'] ?? [], fn() => yapilandirma()['veritabani']),
    ['ortam' => ['UYG_VERITABANI' => 'deneme.db']],
);
RuntimeException: eksik ortam değişkeni: UYG_ANAHTAR
anahtar okundu: evet
veritabanı adı (ortam değişkeninden) → ortam
    ortam değiştirdi

Son ölçüm sorunun cevabıdır. Dağıtımı yapan taraf UYG_VERITABANI değişkenini deneme.db yaptığında, hiçbir satırı değişmeyen kod farklı bir ad döndürür.

DO8. Karar sırası istemci, üçüncü taraf, ortam, sunucudur. Burada istemcinin ve üçüncü tarafın sapması tanımlı değildir, çünkü değeri ne isteğin göndericisi ne bir dış servis verir; tek sapma ortamındır ve sonucu değiştirdi. Taraf ortamdır. Ortamın yüzeyi en dardır: değişkenin değerini dağıtımı yapan verir; çalışan kod putenv() ile yalnız kendi sürecinin ortamını değiştirebilir, ölçümdeki sapma da böyle uygulanır. Bu darlık güvenliği değil, sorumluluğu belirler. Yanlış bir değerin sahibi artık kodu yazan değil dağıtımı yapandır.

DO9. Gizli değerler bu yüzden koda yazılmaz, ortamdan okunur. Koddaki bir anahtar depoya girer, depoyu okuyan herkesin eline geçer ve değişmesi için kodun yeniden dağıtılması gerekir. Ortamdaki anahtar depoda yoktur ve dağıtımı yapanın elinde döndürülebilir. Bu bir sızıntıyı imkânsız yapmaz; yalnız sızıntı yüzeyini kod deposundan dağıtım katmanına çeker.

Varsayılanın Sınırı

Varsayılan değer bir kolaylıktır ve bir riski de taşır. UYG_VERITABANI unutulursa uygulama uygulama.db ile açılır ve hiçbir şey olmamış gibi çalışır. Geliştirme makinesinde bu istenen davranıştır. Üretimde ise yanlış veritabanına yazmak, açılmayı reddetmekten daha pahalıdır. Bu yüzden varsayılan yalnız yanlış değerin zararsız olduğu değişkenlere verilir; zararlı olabilecek her değişken ortam()’ın ikinci argümanını boş bırakır ve eksikliği bir hataya çevirir.

Hatanın iletisi de bir tasarım kararıdır. İleti değişkenin adını söyler, değerini söylemez. Adı söylemek dağıtımı yapana neyin eksik olduğunu gösterir; değeri söylemek, değer gizliyse, günlüğe sızdırmak olur. Ölçümün ilk satırı bu iletiyi basar ve yalnız ad görünür.

Bir değişkenin kimin elinde olduğu da yapılandırmanın parçasıdır. Ortam değişkenini süreci başlatan kurar; çalışan süreç putenv() ile yalnız kendi ortamını değiştirebilir, başka bir sürecin ortamını değiştiremez. Bu, istemciden gelen bir değerle ortamdan gelen değer arasındaki asıl farktır: istemcinin değeri her istekle yeniden gelir ve her istekte farklı olabilir, ortamın değeri süreç başlarken gelir ve kod onu açıkça değiştirmedikçe süreç boyunca aynı kalır.

Sınırlayıcı Ölçüm

Yapılandırmanın alternatifi değeri koda yazmaktır. Aynı veritabanı adı bir sabit olarak kodda durursa ortam onu değiştirebilir mi?

<?php
// sabit.php — kodda sabit yazılan değeri ortam değiştiremez
declare(strict_types=1);

require 'taraf.php';
require 'yapilandirma.php';

const SABIT_VERITABANI = 'uygulama.db';

function sabitVeritabani(): string
{
    return SABIT_VERITABANI;
}

tarafRaporu(
    'veritabanı adı (kodda sabit)',
    fn(array $s) => ortamla($s['ortam'] ?? [], fn() => sabitVeritabani()),
    ['ortam' => ['UYG_VERITABANI' => 'deneme.db']],
);
veritabanı adı (kodda sabit) → sunucu
    ortam değiştiremedi

DO10. Değiştiremedi ve sonuç sunucudur. Sabit, ortamın sapmasını görmezden geldi: UYG_VERITABANI deneme.db olsa da kod uygulama.db döndürdü. Aynı ad, aynı kodda, her ortamda aynı kalır.

Bu ölçüm sabitin savunulabilir olduğunu söylemez. Sabit ortamın sapmasına karşı sağlamdır ama değeri değiştirmek kodu değiştirmek ve yeniden dağıtmak demektir. Geliştirici makinesinde ve üretimde aynı ad kullanılamıyorsa, ortamlar arasında taşınan şey kodun kendisidir ve her ortam için ayrı bir sürüm gerekir. Sabit sunucuya döner, ama bedeli taşınabilirliktir.

Özet

  • Dağıtıma bağlı değerler (bağlantı adı, anahtar) koda yazılmaz; ortam değişkeninden okunur ve tek bir yapılandırma katmanında toplanır.
  • Varsayılan değer makul bir değer varsa verilir; anahtar gibi vazgeçilmez bir değer eksikse RuntimeException ile uygulama açılırken durur.
  • Gizli değer çıktıya, günlüğe ya da hata iletisine basılmaz.
  • Aynı kod, UYG_VERITABANI değişince farklı ad döndürür. Bu dersin ölçü sınıfı ortamdır: değeri kodu yazan değil dağıtımı yapan belirler.
  • Sınır: kodda sabit yazılan değer sunucuda kalır ve ortam onu değiştiremez, ama ortamlar arasında taşınamaz.

Sonraki Adım

Üç ders, durumun nerede durduğunu ve onu kimin değiştirebildiğini ölçtü: çerezde istemci, oturumda sunucu, yapılandırmada ortam. Sonraki konu veri erişimine geçer ve aynı soruyu veritabanına sorar: okunan bir değerin tipini kod mu belirliyor, yoksa kodun çalıştığı ortam mı?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat