Nesneler dizisi için PHPDoc türü ipucu?


417

Yani, PHPDoc'da türünün @varipucu vermek için üye değişken bildiriminin yukarısında belirtilebilir. Sonra bir IDE, örn. PHPEd, ne tür bir nesne ile çalıştığını bilecek ve bu değişken için bir kod bilgisi sağlayabilecektir.

<?php
  class Test
  {
    /** @var SomeObj */
    private $someObjInstance;
  }
?>

Daha sonra bu nesneler arasında yineleme yaparken uygun bir ipucu elde edebilmek için bir dizi nesneye aynı şeyi yapmam gerekene kadar bu harika çalışıyor.

Yani, üye değişkeninin SomeObjs dizisi olduğunu belirtmek için bir PHPDoc etiketi bildirmenin bir yolu var mı? @vardizi yeterli değildir ve @var array(SomeObj)örneğin geçerli görünmemektedir.


2
Bu Netbeans 6.8 geliştirici blogunda IDE'nin artık dizi üyesi türünü çıkaracak
John Carter

3
@therefromhere: bağlantınız koptu. Yeni URL olduğunu düşünüyorum: blogs.oracle.com/netbeansphp/entry/php_templates_improved
DanielaWaranie

Benim gibi insanlar için, yanından geçip bir cevap arıyor: PHPStorm kullanıyorsanız, en çok oylanan cevaba bakın: belirli bir ipucu var! stackoverflow.com/a/1763425/1356098 (bu, örneğin PHPEd istediğinden OP için yanıt olması gerektiği anlamına gelmez)
Erenor Paz

Yanıtlar:


337

kullanın:

/* @var $objs Test[] */
foreach ($objs as $obj) {
    // Typehinting will occur after typing $obj->
}

satır içi değişkenleri belirtirken ve

class A {
    /** @var Test[] */
    private $items;
}

sınıf özellikleri için.

PHPDoc (ve Zend Studio ve Netbeans gibi IDE'ler) bu seçeneğe sahip olmadığında '09'dan önceki yanıt:

Yapabileceğiniz en iyi şey,

foreach ($Objs as $Obj)
{
    /* @var $Obj Test */
    // You should be able to get hinting after the preceding line if you type $Obj->
}

Bunu Zend Studio'da çok yapıyorum. Diğer editörleri bilmiyorum, ama çalışması gerekiyor.


3
Bu mantıklı ama PHPEd 5.2 için işe yaramadı. Çalıştığım tek şey foreach ($ Objs as / ** @var Test * / $ Obj), korkunç çirkin. :(
Artem Russakovskii

14
Netbeans 7'de not, sadece bir yıldız işaretinizin olması önemli görünüyor - /** @var $Obj Test */çalışmıyor.
contrebis

3
@contrebis: "@var" geçerli bir docblock etiketidir. Yani IDE'niz "/ ** ... /" bir docblock içinde desteklemese ve sadece "/ ... * /" içindeki "@var" 'ı desteklese bile - lütfen, lütfen doğru docblock'unuzu değiştirmeyin. IDE'nizi standartlara uygun hale getirmek için IDE'nizin hata izleyicisine bir sorun gönderin. Geliştirme ekibinizin / harici geliştiricilerin / topluluğun farklı IDE'ler kullandığını düşünün. Olduğu gibi tutun ve geleceğe hazırlıklı olun.
DanielaWaranie

181
Aşağıya baktığınızdan emin olun! Neredeyse aşağı kaydırma yoktu - BÜYÜK BİR HATA olurdu! Birçok IDE daha iyi sözdizimini destekleyecek! (ipucu: @var Object[] $objects"$ objects" nin bir Object örneği dizisi olduğunu söylüyor.)
Thom Porter

10
/** @var TYPE $variable_name */doğru sözdizimidir; her durumda çalışmadığı için tür ve değişken adının sırasını (yorumlarda daha önce önerildiği gibi) tersine çevirmeyin.
srcspider

893

JetBrains'ten PhpStorm IDE'de şunları kullanabilirsiniz /** @var SomeObj[] */:

/**
 * @return SomeObj[]
 */
function getSomeObjects() {...}

Phpdoc belgeleri , bu yöntem önerir:

Tek bir tür içeren belirtildiğinde, Tür tanımı okuyucuya her dizi öğesinin türünü bildirir. Belirli bir dizi için öğe olarak yalnızca bir Tür beklenir.

Misal: @return int[]


10
Az önce indirdim ve geçen hafta phpstorm kullanıyorum. (Ki özgür olmak için harika) Aptana heck yener. Tam da aradığım şey buydu. Aslında, JavaScript için yaptığınız gibi, tahmin etmeliydim
Juan Mendes

3
Teşekkürler dostum! Tam da aradığım şey buydu. PHPStorm harika.
Erik Schierboom

5
Bu Netbeans'de işe yaramıyor, hayal kırıklığına uğradım. Jetbrains çok güzel araçlar yapar.
Keyo

10
@fishbone @Keyo Bu Netbeans şimdi çalışıyor (en azından 7.1 gece inşa, en azından belki daha erken), ancak geçici bir değişken (bir hata?) İçin ipucu foreach(getSomeObjects() as $obj)işe yaramıyor, ama işe yarıyor$objs = getSomeObjects(); foreach($objs as $obj)
John Carter

2
@var Obj[string]İlişkilendirilebilir diziler için iyi olurdu .
donquixote

59

Netbeans ipuçları:

Üzerinde kod tamamlama almak $users[0]->ve için $this->Kullanıcı sınıfları bir dizi için.

/**
 * @var User[]
 */
var $users = array();

Dizinin türünü, tamamladığınızda sınıf üyeleri listesinde de görebilirsiniz. $this->...


4
PhpStorm 9 EAP'de de çalışır: / ** * @var UserInterface [] * / var $ users = []; // Arayüz uygulayan Objs dizisi
Ronan

NetBeans IDE 8.0.2'de denedim, ama şu anda bulunduğum sınıftan öneriler alıyorum.
Wojciech Jasiński

ayrıca Eclipse 4.6.3'te çalışır (idk hangi sürüm desteğinin tanıtıldığını, ancak çalıştığını ve şu anda kullandığım şeyi)
hanshenrik

Ne yazık ki bu array_pop(), herhangi bir nedenle veya benzer işlevleri kullandıktan sonra çalışmaz . Netbeans'ın bu işlevlerin giriş dizisinin tek bir öğesini döndürdüğünü fark etmediği anlaşılıyor.
William W

29

Bir değişken belirtmek bir nesne dizisidir:

$needles = getAllNeedles();
/* @var $needles Needle[] */
$needles[1]->...                        //codehinting works

Bu Netbeans 7.2'de çalışıyor (kullanıyorum)

Şununla da çalışır:

$needles = getAllNeedles();
/* @var $needles Needle[] */
foreach ($needles as $needle) {
    $needle->...                        //codehinting works
}

Bu nedenle, içinde bildirim kullanmak foreachgerekli değildir.


2
Bu çözüm, benim görüşüme göre kabul edilen cevaptan daha temiz, çünkü /* @var $Obj Test */her seferinde birden fazla kez kullanabilirsiniz ve tür ipucu her seferinde yeni bir ek açıklama ile çalışmaya devam edecektir .
Henry

: Burada iki sorunları görmek 1. ile uygun phpdoc başlar /** 2. doğru biçimidir@var <data-type> <variable-name>
Christian

@Christian 1: ana soru phpdoc değil, typehinting 2: Doğru cevap, diğer cevaplara göre bile söylediğiniz gibi değil. Aslında, yorumunuzla ilgili 2 sorun görüyorum ve neden doğru formatla kendi cevabınızı verdiğinizi merak ediyorum
Highmastdon

1. Typehinting phpdoc ile çalışır ... docblock'u kullanmazsanız, IDE'niz rastgele bir yorumda yazdıklarınızı tahmin etmeye çalışmaz. 2. Doğru cevap, bazı diğer cevapların da söylediğim gibi yukarıda belirttiğim; değişken adından önceki veri türü . 3. Başka bir cevap yazmadım çünkü sorunun başka bir cevaba ihtiyacı yok ve sadece kodunuzu düzenlemek istemiyorum.
Christian

24

PSR-5: PHPDoc bir çeşit Generics tarzı gösterim önerir.

Sözdizimi

Type[]
Type<Type>
Type<Type[, Type]...>
Type<Type[|Type]...>

Bir Koleksiyondaki değerler başka bir dizi ve hatta başka bir Koleksiyon olabilir.

Type<Type<Type>>
Type<Type<Type[, Type]...>>
Type<Type<Type[|Type]...>>

Örnekler

<?php

$x = [new Name()];
/* @var $x Name[] */

$y = new Collection([new Name()]);
/* @var $y Collection<Name> */

$a = new Collection(); 
$a[] = new Model_User(); 
$a->resetChanges(); 
$a[0]->name = "George"; 
$a->echoChanges();
/* @var $a Collection<Model_User> */

Not: Bir IDE'nin kod yardımı yapmasını bekliyorsanız, IDE'nin PHPDoc Generic-style collection gösterimini destekleyip desteklemediği hakkında başka bir soru daha vardır.

Cevabım bu soruya .


Genel gösterim PSR-5'ten kaldırıldı
zored

11

Temiz kod okumayı ve yazmayı tercih ediyorum - Robert C. Martin tarafından "Clean Code" da belirtildiği gibi. Kredisini takip ederken geliştiricinin (API'nızın kullanıcısı olarak) dizinizin (dahili) yapısını bilmesini istememeniz gerekir.

API kullanıcısı şunu sorabilir: Bu yalnızca bir boyutu olan bir dizi mi? Nesneler çok boyutlu bir dizinin tüm düzeylerine yayılmış mı? Tüm nesnelere erişmek için kaç tane iç içe döngü (foreach vb.) Gerekir? Bu dizide ne tür nesneler "depolanır"?

Ana hatlarıyla belirttiğiniz gibi, o diziyi (nesneleri içeren) tek boyutlu bir dizi olarak kullanmak istersiniz.

Nishi tarafından belirtildiği gibi şunları kullanabilirsiniz:

/**
 * @return SomeObj[]
 */

bunun için.

Ama tekrar: farkında olun - bu standart bir docblock gösterimi değildir. Bu gösterim bazı IDE üreticileri tarafından tanıtıldı.

Tamam, tamam, bir geliştirici olarak "[]" in PHP'deki bir diziye bağlı olduğunu biliyorsunuz. Ancak normal PHP bağlamında bir "şey []" ne anlama gelir? "[]" şu anlama gelir: "bir şey" içinde yeni bir öğe yaratmak. Yeni unsur her şey olabilir. Ancak ifade etmek istediğiniz şey: aynı türdeki nesnelerin dizisi ve tam türü. Gördüğünüz gibi, IDE üreticisi yeni bir bağlam sunuyor. Öğrenmeniz gereken yeni bir bağlam. Diğer PHP geliştiricilerinin öğrenmesi gereken yeni bir bağlam (docblock'larınızı anlamak için). Kötü stil (!).

Dizinizin bir boyutu olduğundan, "nesne dizisi" ni "liste" olarak adlandırmak isteyebilirsiniz. "Liste" nin diğer programlama dillerinde çok özel bir anlamı olduğunu unutmayın. Mesela "koleksiyon" demek daha iyi olurdu.

Unutmayın: tüm OOP seçeneklerini sağlayan bir programlama dili kullanırsınız. Dizi yerine bir sınıf kullanın ve sınıfınızı bir dizi gibi gezilebilir yapın. Örneğin:

class orderCollection implements ArrayIterator

Veya dahili nesneleri çok boyutlu bir dizi / nesne yapısı içinde farklı düzeylerde saklamak istiyorsanız:

class orderCollection implements RecursiveArrayIterator

Bu çözüm dizinizi "orderCollection" türündeki bir nesne ile değiştirir, ancak şu ana kadar IDE'nizde kod tamamlamayı etkinleştirmeyin. Tamam. Sonraki adım:

Arayüz tarafından tanıtılan yöntemleri docblocks ile uygulayın - özellikle:

/**
 * [...]
 * @return Order
 */
orderCollection::current()

/**
 * [...]
 * @return integer E.g. database identifier of the order
 */
orderCollection::key()

/**
 * [...]
 * @return Order
 */
orderCollection::offsetGet()

Aşağıdakiler için tür ipucunu kullanmayı unutmayın:

orderCollection::append(Order $order)
orderCollection::offsetSet(Order $order)

Bu çözüm aşağıdakileri sunmayı bırakır:

/** @var $key ... */
/** @var $value ... */

Zahymaka'nın yanıtıyla doğruladığı gibi, kod dosyalarınızın her yerinde (örn. döngüler içinde). API kullanıcısı, kod tamamlama için bu docblock'ları tanıtmak zorunda değildir. @ Geri dönüşünün tek bir yerde olması yedekliliği (@var) mümkün olduğunca mutch azaltır. Serpin "@var ile docBlocks" kodunuzu en kötü okunabilir yapar.

Sonunda bitti. Başarmak zor görünüyor mu? Bir ceviz kırmak için balyoz almak gibi mi? O arayüzlere ve temiz kodlara aşina olduğunuzdan, gerçek değil. Unutmayın: kaynak kodunuz bir kez yazılır / çok okunur.

IDE'nizin kodunun tamamlanması bu yaklaşımla çalışmazsa, daha iyi olana geçin (örn. IntelliJ IDEA, PhpStorm, Netbeans) veya IDE üreticinizin sorun izleyicisine bir özellik isteği gönderin.

Eğitmenim olduğu ve bana çok güzel şeyler öğrettiği için Christian Weiss'a (Almanya'dan) teşekkürler. PS: Ben ve onunla XING'de buluş.


Bu "doğru" yol gibi görünüyor, ama Netbeans ile çalışmak için elde edemezsiniz. Biraz örnek verdim
fehrlich

2
Belki 2012'de bu bir "standart değildi", ancak şimdi phpDoc'un yerleşik işlevselliği olarak tanımlanıyor.
Wirone

@Wirone gibi görünüyor phpDocumentor ide üreticilerine bir tepki olarak kılavuzuna ekler. Geniş bir alet desteğine sahip olsanız bile, bunun en iyi uygulama olduğu anlamına gelmez. SomeObj [] yıllar önce yapılan, requir_once, include ve include_once gibi daha fazla projede yayılmaya başlar. Otomatik yükleme ile bu ifadelerin görünümü% 5'in altına düşer. Umarım SomeObj [] yukarıdaki yaklaşım lehine önümüzdeki 2 yıl içinde aynı orana düşer.
DanielaWaranie

1
Nedenini anlamıyorum? Bu çok basit ve net bir gösterimdir. Gördüğünüzde, SomeObj[]bunun iki boyutlu bir SomeObjörnek dizisi olduğunu ve bununla ne yapacağınızı biliyorsunuz. Ben "temiz kod" kredi takip etmez sanmıyorum.
Wirone

Cevap bu olmalı. Bununla birlikte, tüm IDE destekleri @return <className>için current()ve tüm çocuklar için yaklaşım yoktur . PhpStorm destekler bu yüzden bana çok yardımcı oldu. Teşekkürler dostum!
Pavel

5

kullanım array[type]Zend Studio'da .

Zend Studio, içinde array[MyClass]veya array[int]hatta array[array[MyClass]]çalışan harika.


5

NetBeans 7.0'da (çok daha düşük olabilir), dönüş türünü "Metin nesneleriyle dizi" olarak @return Texttanımlayabilir ve kod ipucu işe yarayacaktır:

Düzenle: örneği @Bob Fanger önerisiyle güncelledi

/**
 * get all Tests
 *
 * @return Test|Array $tests
 */
public function getAllTexts(){
    return array(new Test(), new Test());
}

ve sadece kullanın:

$tests =  $controller->getAllTests();
//$tests->         //codehinting works!
//$tests[0]->      //codehinting works!

foreach($tests as $text){
    //$test->      //codehinting works!
}

Mükemmel değil ama o zaman sadece "karışık" bırakmak daha iyidir, bu da hiçbir değer getirmez.

CONS diziyi hataları atacak Metin Nesnesi olarak basmanıza izin verilir.


1
"@Return array | Test Some description" kullanıyorum. ki bu da aynı davranışı tetikler ancak biraz daha açıklayıcıdır.
Bob Fanger

1
Bu bir çözüm , bir çözüm değil. Burada söylediğiniz şey "bu işlev 'Test' ya da bir dizi türünde bir nesne döndürebilir" dir. Ancak, teknik olarak dizide ne olabileceği hakkında hiçbir şey söylemez.
Byson

5

DanielaWaranie onu cevapta belirtildiği üzere - Eğer $ collectionObject içinde $ ürün üzerinde ilerlerken $ öğenin türünü belirtmek için bir yol yoktur: Ekle @return MyEntitiesClassNameetmek current()ve dinlenme Iteratorve ArrayAccess-Kullanılan hangi dönüş değerleri.

Boom! /** @var SomeObj[] $collectionObj */Üzerinden gerek yok foreachve toplama nesnesi ile doğru çalışır, koleksiyon olarak tarif edilen belirli bir yöntemle koleksiyonu döndürmeye gerek yoktur @return SomeObj[].

Tüm IDE'nin desteklediğinden şüphelenmiyorum, ancak PhpStorm'da mükemmel çalışıyor, bu da beni daha mutlu ediyor.

Misal:

class MyCollection implements Countable, Iterator, ArrayAccess {

    /**
     * @return User
     */
    public function current() {
        return $this->items[$this->cursor];
    }

    //... implement rest of the required `interface` methods and your custom
}

Bu yanıtı yayınlamak için ne kadar faydalı olacaktım

Benim durumumda current()ve yöntemlerin geri kalanı interfacetoplama Abstractsınıfında uygulanır ve sonunda ne tür varlıkların koleksiyonda saklanacağını bilmiyorum.

İşte hile: Soyut sınıfta dönüş türü belirtmeyin, bunun yerine @methodbelirli toplama sınıfının açıklamasında PhpDoc instuction kullanın .

Misal:

class User {

    function printLogin() {
        echo $this->login;
    }

}

abstract class MyCollection implements Countable, Iterator, ArrayAccess {

    protected $items = [];

    public function current() {
        return $this->items[$this->cursor];
    }

    //... implement rest of the required `interface` methods and your custom
    //... abstract methods which will be shared among child-classes
}

/**
 * @method User current()
 * ...rest of methods (for ArrayAccess) if needed
 */
class UserCollection extends MyCollection {

    function add(User $user) {
        $this->items[] = $user;
    }

    // User collection specific methods...

}

Şimdi, sınıfların kullanımı:

$collection = new UserCollection();
$collection->add(new User(1));
$collection->add(new User(2));
$collection->add(new User(3));

foreach ($collection as $user) {
    // IDE should `recognize` method `printLogin()` here!
    $user->printLogin();
}

Bir kez daha: Tüm IDE'nin desteklemediğinden şüpheleniyorum, ancak PhpStorm destekliyor. Sizinkini deneyin, sonuçları yorumda yayınlayın!


Bu kadar itmek için fiş, ama ne yazık ki hala iyi eski java jenerik türleri yerine bir koleksiyon uzmanlaşmak için kendimi çözebilir .... yuck '
Sebas

Teşekkür ederim. Statik bir yöntemi nasıl yazabilirsiniz?
Yevgeniy Afanasyev

3

Partiye geç kaldığımı biliyorum, ama son zamanlarda bu sorun üzerinde çalışıyorum. Kabul edilen cevap, doğru olsa, çünkü umut birisi bunu görür değil bunu yapmanın en iyi yolu . En azından PHPStorm'da değil, NetBeans'i test etmedim.

En iyi yol, yerel dizi türlerini kullanmak yerine ArrayIterator sınıfını genişletmektir. Bu, örnek düzeyinde değil, sınıf düzeyinde bir ipucu yazmanıza olanak tanır, yani kodunuz boyunca değil, sadece bir kez PHPDoc'a ihtiyacınız vardır (bu sadece dağınık değildir ve DRY'yi ihlal eder, ancak söz konusu olduğunda da sorunlu olabilir) yeniden düzenleme - PHPStorm'un yeniden düzenleme yaparken PHPDoc'u eksik alışkanlığı vardır)

Aşağıdaki koda bakın:

class MyObj
{
    private $val;
    public function __construct($val) { $this->val = $val; }
    public function getter() { return $this->val; }
}

/**
 * @method MyObj current()
 */
class MyObjCollection extends ArrayIterator
{
    public function __construct(Array $array = [])
    {
        foreach($array as $object)
        {
            if(!is_a($object, MyObj::class))
            {
                throw new Exception('Invalid object passed to ' . __METHOD__ . ', expected type ' . MyObj::class);
            }
        }
        parent::__construct($array);
    }

    public function echoContents()
    {
        foreach($this as $key => $myObj)
        {
            echo $key . ': ' . $myObj->getter() . '<br>';
        }
    }
}

$myObjCollection = new MyObjCollection([
    new MyObj(1),
    new MyObj('foo'),
    new MyObj('blah'),
    new MyObj(23),
    new MyObj(array())
]);

$myObjCollection->echoContents();

Buradaki anahtar, ArrayIterator öğesinden @method MyObj current()devralınan dönüş türünü geçersiz kılan PHPDoc'tur mixed. Sınıfsal özellikleri kullanılarak yineleme zaman bu PHPDoc aracının dahil edilmesi foreach($this as $myObj), o zaman kod tamamlama elde değişken atıfta$myObj->...

Bana göre, bunu başarmanın en iyi yolu (en azından PHP Yazılmış Dizileri tanıtana kadar, eğer yaparlarsa), yinelenen sınıfta yineleyici türünü bildiriyoruz, kod boyunca dağılmış sınıf örnekleri üzerinde değil.

Burada ArrayIterator'ı genişletmek için tam bir çözüm göstermedim, bu nedenle bu tekniği kullanırsanız, şunları da yapmak isteyebilirsiniz:

  • Gibi yöntemler için gerekli olan diğer sınıf düzeyindeki phpdoc dahil edin offsetGet($index)venext()
  • Akıl sağlığı kontrolünü is_a($object, MyObj::class)yapıcıdan özel bir yönteme taşıyın
  • Bu gibi yöntem geçersiz kılmalarından bu (şimdi özel) sağlık kontrolü olarak adlandırın offsetSet($index, $newval)veappend($value)

Çok güzel ve temiz bir çözüm! :)
Marko Šutija

2

Problem şu @var sadece tek bir türü gösterebilir - Karmaşık bir formül içermez. "Foo dizisi" için bir sözdiziminiz varsa, neden orada durun ve "dizi dizisi için 2 Foo ve üç Bar" içeren bir sözdizimi eklemiyorsunuz? Öğelerin bir listesinin belki de bundan daha genel olduğunu anlıyorum, ancak kaygan bir eğim.

Şahsen ben @var Foo[]"Foo bir dizi" belirtmek için kullanılan bazı zamanlar var, ama IDE tarafından desteklenmiyor.


5
C / C ++ ile ilgili sevdiğim şeylerden biri, aslında türlerin bu seviyeye kadar takip etmesidir. Kayması çok hoş bir eğim olurdu.
Brilliand

2
(Sürüm I kullanımı olduğunu, en azından), ancak yani biraz ajustment ile NetBeans 7.2 ile destekleniyor: /* @var $foo Foo[] */. Bunun hakkında aşağıda bir cevap yazdım. Bu, foreach(){}döngüler içinde de kullanılabilir
Highmastdon

1
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
    <?php
    // Type hinting now works:
    $model->getImage();
    ?>
<?php endforeach; ?>

5
hangi IDE'ler bunu destekliyor?
philfreo

21
Bu çok çirkin. Böyle bir programlamaya başladığınızda kodu temizlemeye veda edin.
halfpastfour.am

Bunun yerine dizinin içeriğini tanımlayarak cevabım bakın:
cevabıma bakın

-5

Çalışan bir şey buldum, hayat kurtarabilir!

private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
   $user instanceof User;
   echo $user->getName();
}

11
tek sorun, yalnızca IDE'niz tarafından kullanılan yürütülecek ek kodun girilmesidir. Bunun yerine yorumların içinde tür ipucunu tanımlamak çok daha iyidir.
Ben Rowe

1
Vay canına, bu harika çalışıyor. Ek kod ile sonuçlanırsınız, ancak zararsız görünüyor. Yapmaya başlayacağım: $ x instanceof Y; // typehint
Igor Nadj

3
Docblock veya denetimlere dayalı olarak kod tamamlama sağlayan bir IDE'ye geçin. IDE dosyanızı değiştirmek istemiyorsanız, IDE'nizin sorun izleyicisinde bir özellik isteği.
DanielaWaranie

1
Tür doğru değilse bir istisna atarsa, çalışma zamanı türü denetimi için yararlı olabilir. If ...
lilbyrdie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.