ทะเยอทะยานและ Setter?


203

ฉันไม่ใช่นักพัฒนา PHP ดังนั้นฉันจึงสงสัยว่าใน PHP นิยมใช้ตัวรับ / setters อย่างชัดเจนในรูปแบบ OOP บริสุทธิ์พร้อมฟิลด์ส่วนตัว (อย่างที่ฉันชอบ):

class MyClass {
    private $firstField;
    private $secondField;

    public function getFirstField() {
        return $this->firstField;
    }
    public function setFirstField($x) {
        $this->firstField = $x;
    }
    public function getSecondField() {
        return $this->secondField;
    }
    public function setSecondField($x) {
        $this->secondField = $x;
    }
}

หรือเพียงแค่ฟิลด์สาธารณะ:

class MyClass {
    public $firstField;
    public $secondField;
}

ขอบคุณ


7
หลังจากลองใช้รหัสจากคำตอบฉันใช้รหัสที่คุณใช้ในคำถาม ช่างน่าเศร้าเหลือเกิน :-(
sumid

9
PHPstorm ... สร้าง> ตัวรับและตัวตั้งค่า == win
DevDonkey

@DevDonkey ไม่ชนะเลย สำหรับการเก็บข้อมูลที่มีโครงสร้างให้ใช้อาร์เรย์แทน @: ทำเครื่องหมายนี่ไม่ใช่สิ่งที่เป็นวัตถุหรือสำหรับ Getters และ setters ชั่วร้าย: yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Kubo2

คำตอบ:


222

คุณสามารถใช้วิธีมายากล PHP และ__get__set

<?php
class MyClass {
  private $firstField;
  private $secondField;

  public function __get($property) {
    if (property_exists($this, $property)) {
      return $this->$property;
    }
  }

  public function __set($property, $value) {
    if (property_exists($this, $property)) {
      $this->$property = $value;
    }

    return $this;
  }
}
?>

15
ฉันคิดว่าคุณหมายถึงและ__get __setมีขีดล่างสองอันไม่ใช่อันเดียว นี่คือลิงค์โดยตรงไปยังส่วนด้านขวาของหน้า: php.net/manual/en/… (+1 สำหรับคำตอบที่ถูกต้อง)
Computerish

28
ประโยชน์ที่ได้รับต่อpublicทรัพย์สินมีอะไรบ้างหากไม่มีการตรวจสอบ / การสุขาภิบาล?
KingCrunch

7
@KingCrunch นี่เป็นเพียงตัวอย่าง ตัวอย่างที่หลอกตามากสำหรับทรัพยากรที่มีประสิทธิภาพ
Davis Peixoto

10
นั่นไม่ใช่ตัวตั้งตัวและทะเยอทะยานจริงๆ โดยทั่วไปฉันต้องการสำหรับแต่ละคุณสมบัติการใช้งานที่แตกต่างกันของการทะเยอทะยาน!
sumid

79
โปรดอย่า: ด้วยวิธีการที่วิเศษคุณจะต้องเสียคุณสมบัติที่เกี่ยวข้องกับคุณภาพเกือบทุกอย่างใน IDE หลายตัว (แม้เป็นจำนวนมาก): การทำให้สมบูรณ์อัตโนมัติการสืบทอด PHP ที่ชัดเจนการตีความ PHP ที่รวดเร็ว & การสร้างและเอาท์พุท PHPDoc cf เลย stackoverflow.com/a/6184893/490589
Ronan

113

ทำไมต้องใช้ getters และ setters

  1. ความสามารถในการปรับขนาด : มันง่ายกว่าในการสร้าง getter ให้ง่ายกว่าการค้นหาค่า var ทั้งหมดในรหัสโครงการ
  2. การดีบัก : คุณสามารถวางเบรกพอยต์ที่ setters และ getters
  3. ทำความสะอาด : ฟังก์ชั่นเวทย์มนตร์ไม่ได้เป็นทางออกที่ดีสำหรับการเขียนน้อยกว่า IDE ของคุณจะไม่แนะนำรหัส ใช้เท็มเพลตที่ดียิ่งขึ้นสำหรับตัวรับสัญญาณที่รวดเร็ว

การมอบหมายโดยตรงและ getters / setters


7
ถ้าคุณใช้ @property, IDE ของคุณจะแนะนำรหัส (ทดสอบด้วย PhpStorm 7)
Alex2php

41

Google ได้เผยแพร่คู่มือเกี่ยวกับการเพิ่มประสิทธิภาพของ PHP แล้วและข้อสรุปคือ:

ไม่มีทะเยอทะยานและ setter PHP เพิ่มประสิทธิภาพ

และไม่มีคุณต้องไม่ใช้วิธีการมายากล สำหรับ PHP, Magic Method นั้นชั่วร้าย ทำไม?

  1. พวกมันยากที่จะดีบั๊ก
  2. มีผลกระทบด้านลบต่อประสิทธิภาพ
  3. พวกเขาต้องการการเขียนโค้ดเพิ่มเติม

PHP ไม่ใช่ Java, C ++ หรือ C # PHP มีความแตกต่างและมีบทบาทแตกต่างกัน


10
ฉันมักจะเห็นด้วยกับความคิดนั้น ที่ดีกว่า$dog->name = 'fido' $dog->setName('fido')เมื่อทำการผ่าสมบัติ (เช่น: $dog->increaseAge(1)ฉันสามารถสร้างวิธีการตรวจสอบที่จำเป็นและทำให้กลายพันธุ์นั้นได้ แต่การกระทำบางอย่างนั้นไม่จำเป็นต้องมีการกลายพันธุ์ในแง่นั้นจริงๆ
Charlie Schliesser

11
บทความไม่ได้บอกว่า " ไม่ " มันบอกว่า
Brett Santore

1
มันฟื้นขึ้นมา: web.archive.org/web/20140625191431/https://…

13
มันปลอดภัยที่จะสมมติว่าบทความที่เขียนโดย Google ที่มีหัวเรื่อง "เคล็ดลับประสิทธิภาพ PHP" ไม่ได้มีวัตถุประสงค์เพื่อแนะนำรูปแบบการเข้ารหัสที่ดี แต่การใช้รหัสอย่างรวดเร็ว บทที่เกี่ยวข้องกับ setters และ getters มีข้อความระบุว่า "หลีกเลี่ยงการเขียน setters และ getters ที่ไร้เดียงสา" และตัวอย่างของโค้ดคือ: Naive มันตั้งค่าและรับเพียงตัวแปรโดยไม่มีการตรวจสอบใด ๆ สุนัขเซทเทอร์ / ทะเยอทะยานแบบนี้ไร้ประโยชน์ การตรวจสอบความถูกต้องภายใน setter (เพียงใช้คำใบ้ประเภทสำหรับอาร์กิวเมนต์ method) จะทำให้ setters / getters มีประโยชน์เพราะตอนนี้โค้ดของคุณรู้ว่ามันเกี่ยวข้องกับอะไร
Sven

3
นี่เหมือนกับบอกว่าสไตล์อินไลน์ดีกว่า แน่นอนประสิทธิภาพดีขึ้น แต่มันเป็นรหัสที่ดีกว่า ฉันไม่ทราบว่าวิศวกรของ Google ใช้ php อยู่แล้ว
Claudiu Creanga

13

การห่อหุ้มมีความสำคัญในภาษา OO ใด ๆ ความนิยมไม่มีอะไรเกี่ยวข้องกับมัน ในภาษาที่พิมพ์แบบไดนามิกเช่น PHP มีประโยชน์อย่างยิ่งเพราะมีวิธีการเล็กน้อยเพื่อให้แน่ใจว่าคุณสมบัติเป็นประเภทเฉพาะโดยไม่ต้องใช้ตัวตั้งค่า

ใน PHP งานนี้:

class Foo {
   public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";

ใน Java มันไม่ได้:

class Foo {
   public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error

การใช้วิธีการเวทย์มนตร์ ( __getและ__set) ใช้งานได้ แต่เมื่อเข้าถึงคุณสมบัติที่มีทัศนวิสัยต่ำกว่าขอบเขตปัจจุบันที่สามารถเข้าถึงได้ สามารถทำให้คุณปวดหัวได้อย่างง่ายดายเมื่อพยายามดีบั๊กหากไม่ได้ใช้อย่างถูกต้อง


7
ตัวรับและตัวตั้งค่าไม่ได้นำการห่อหุ้ม Encapsulation == วัตถุทำอะไรกับข้อมูลของตัวเองแทนที่จะให้พวกเขาออกไปข้างนอก Getters และ setters ไม่ใช่เครื่องมือสำหรับการบังคับใช้ประเภทในภาษาที่พิมพ์แบบไดนามิกเช่น PHP
smentek

14
@smentek: คุณหายไปอย่างชัดเจนครึ่งหนึ่งของการห่อหุ้มจริงๆ
netcoder

2
การอัปเดตสำหรับสิ่งนี้สำหรับทุกคนที่กำลังมองหา PHP 7.4 จะมาพร้อมกับการสนับสนุนคุณสมบัติที่พิมพ์ ดังนั้นคุณสามารถประกาศ$barเป็นintตัวอย่างแรกได้: wiki.php.net/rfc/typed_properties_v2
Kevin

7

หากคุณต้องการใช้ฟังก์ชัน __call คุณสามารถใช้วิธีนี้ได้ มันใช้ได้กับ

  • GET => $this->property()
  • SET => $this->property($value)
  • GET => $this->getProperty()
  • SET => $this->setProperty($value)

kalsdas

public function __call($name, $arguments) {

    //Getting and setting with $this->property($optional);

    if (property_exists(get_class($this), $name)) {


        //Always set the value if a parameter is passed
        if (count($arguments) == 1) {
            /* set */
            $this->$name = $arguments[0];
        } else if (count($arguments) > 1) {
            throw new \Exception("Setter for $name only accepts one parameter.");
        }

        //Always return the value (Even on the set)
        return $this->$name;
    }

    //If it doesn't chech if its a normal old type setter ot getter
    //Getting and setting with $this->getProperty($optional);
    //Getting and setting with $this->setProperty($optional);
    $prefix = substr($name, 0, 3);
    $property = strtolower($name[3]) . substr($name, 4);
    switch ($prefix) {
        case 'get':
            return $this->$property;
            break;
        case 'set':
            //Always set the value if a parameter is passed
            if (count($arguments) != 1) {
                throw new \Exception("Setter for $name requires exactly one parameter.");
            }
            $this->$property = $arguments[0];
            //Always return the value (Even on the set)
            return $this->$name;
        default:
            throw new \Exception("Property $name doesn't exist.");
            break;
    }
}

2
@ krzysztof-przygoda: "วิธีการเวทย์มนตร์" นี้มักจะมาพร้อมกับราคา พวกเขาต้องใช้การสอบถามซ้ำproperty_exists(get_class($this), $name)และการเรียกซ้ำช้า มีวิธี y ที่จะบรรเทาปัญหานี้ได้ด้วยการแคช แต่มันจะช้ากว่าการสร้าง getters และ setters ด้วยมือ ฉันแค่เขียนมันเป็นทางเลือก ฉันไม่แนะนำให้ใช้ "วิธีการเวทย์มนตร์" เวลาพิเศษในการสร้างผู้ได้รับและผู้ตั้งค่ามักไม่มีนัยสำคัญ
J-Rou

7

นอกเหนือจากคำตอบที่ยอดเยี่ยมและเป็นที่ยอมรับแล้วในที่นี้ฉันต้องการขยาย PHP โดยไม่มี setters / getters

PHP ไม่ได้มีความทะเยอทะยานและหมาไวยากรณ์ มันมีวิธีการsubclassed หรือเวทมนต์เพื่ออนุญาตให้ "hooking" และแทนที่กระบวนการค้นหาคุณสมบัติตามที่ Daveอธิบาย

Magicช่วยให้เราโปรแกรมเมอร์ขี้เกียจทำมากขึ้นด้วยรหัสน้อยลงในเวลาที่เรามีส่วนร่วมในโครงการและรู้ว่ามันอย่างใกล้ชิด แต่มักจะเสียค่าใช้จ่ายในการอ่าน

ประสิทธิภาพการทำงานทุกฟังก์ชั่นที่ไม่จำเป็นซึ่งเป็นผลมาจากการบังคับใช้โค้ดสถาปัตยกรรมแบบ getter / setter ใน PHP เกี่ยวข้องกับสแต็กเฟรมหน่วยความจำของตัวเองเมื่อทำการเรียกใช้และทำให้รอบการทำงานของ CPU สิ้นเปลือง

ความสามารถในการอ่าน:โค้ดเบสเกิดการบวมของโค้ดบรรทัดซึ่งส่งผลกระทบต่อการนำทางโค้ดเนื่องจาก LOC มากกว่าหมายถึงการเลื่อนที่มากขึ้น

การตั้งค่า: โดยส่วนตัวตามกฎของฉันฉันใช้ความล้มเหลวของการวิเคราะห์รหัสแบบคงที่เป็นสัญญาณเพื่อหลีกเลี่ยงการลงไปบนถนนเวทย์มนตร์ตราบเท่าที่ผลประโยชน์ระยะยาวที่เห็นได้ชัดทำให้ฉันหลงในเวลานั้น

ชักนำ:

อาร์กิวเมนต์ทั่วไปคือความสามารถในการอ่าน ตัวอย่างที่ง่ายต่อการอ่านกว่า$someobject->width $someobject->width()อย่างไรก็ตามไม่เหมือนกับดาวเคราะห์circumferenceหรือwidthซึ่งสามารถสันนิษฐานได้ว่า staticเป็นอินสแตนซ์ของวัตถุเช่น$someobjectซึ่งต้องการฟังก์ชันความกว้างอาจใช้การวัดความกว้างของอินสแตนซ์ของวัตถุ
ดังนั้นความสามารถในการอ่านจึงเพิ่มขึ้นส่วนใหญ่เป็นเพราะโครงร่างการตั้งชื่อที่แน่วแน่และไม่ใช่โดยการซ่อนฟังก์ชั่นที่ส่งออกค่าคุณสมบัติที่กำหนด

__get / __set ใช้:

  • การตรวจสอบความถูกต้องก่อนล่วงหน้าและการสุขาภิบาลล่วงหน้าของค่าคุณสมบัติ

  • สตริงเช่น

    "
    some {mathsobj1->generatelatex} multi
    line text {mathsobj1->latexoutput}
    with lots of variables for {mathsobj1->generatelatex}
     some reason
    "

    ในกรณีนี้generatelatexจะเป็นไปตามรูปแบบการตั้งชื่อของ actionname + methodname

  • กรณีพิเศษที่ชัดเจน

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
    $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()

หมายเหตุ: PHP เลือกที่จะไม่ใช้ไวยากรณ์ getter / setter ฉันไม่ได้อ้างว่า getters / setter โดยทั่วไปแล้วไม่ดี


6
class MyClass {
    private $firstField;
    private $secondField;
    private $thirdField;

    public function __get( $name ) {
        if( method_exists( $this , $method = ( 'get' . ucfirst( $name  ) ) ) )
            return $this->$method();
        else
            throw new Exception( 'Can\'t get property ' . $name );
    }

    public function __set( $name , $value ) {
        if( method_exists( $this , $method = ( 'set' . ucfirst( $name  ) ) ) )
            return $this->$method( $value );
        else
            throw new Exception( 'Can\'t set property ' . $name );
    }

    public function __isset( $name )
    {
        return method_exists( $this , 'get' . ucfirst( $name  ) ) 
            || method_exists( $this , 'set' . ucfirst( $name  ) );
    }

    public function getFirstField() {
        return $this->firstField;
    }

    protected function setFirstField($x) {
        $this->firstField = $x;
    }

    private function getSecondField() {
        return $this->secondField;
    }
}

$obj = new MyClass();

echo $obj->firstField; // works
$obj->firstField = 'value'; // works

echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected

echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private

$obj->secondField = 'value'; // not works, setter not exists

echo $obj->thirdField; // not works, property not exists

isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false

พร้อม!


หม้อต้มมากเกินไป ลองนึกภาพสิ่งนี้อยู่ในทุกชั้นเรียน หลีกเลี่ยง IMO
DarkNeuron

PHP ไม่สนับสนุนผู้ได้รับและผู้ตั้งค่าด้วยเหตุผลเดียวกันกับที่คุณพูดถึง การใช้งานประเภทนี้ส่งผลต่อประสิทธิภาพของสคริปต์ฝั่งเซิร์ฟเวอร์อย่างรุนแรง
joas

ฉันคิดว่าสิ่งนี้ขัดกับคุณสมบัติ 'ส่วนตัว' คุณแค็ปซูลพวกเขา แต่ยังอนุญาตให้เข้าถึงโดยตรง
Koray Küpe

@ KorayKüpeเฉพาะเมื่อทะเยอทะยานถูกกำหนดไว้ ฉันใช้การห่อหุ้มนี้มาก (ด้วยการปรับปรุงมากมาย) และทำงานได้อย่างสมบูรณ์ นอกจากนี้คุณยังสามารถขยายคลาสและใช้งานได้ในรหัสทั้งหมดได้อย่างง่ายดาย
joas

5

ดีPHPจะมีวิธีมายากล__get, __set, __issetและ__unsetซึ่งมักจะเป็นจุดเริ่มต้น อนิจจาเหมาะสม (รับเลย) คุณสมบัติ OO เป็นมากกว่าวิธีเวทย์มนตร์ ปัญหาหลักของการนำ PHP ไปใช้คือวิธีการทางเวทมนตร์ถูกเรียกใช้สำหรับคุณสมบัติที่ไม่สามารถเข้าถึงได้ทั้งหมด ซึ่งหมายความว่าคุณต้องทำซ้ำตัวเอง (เช่นโดยการเรียก property_exists ()) ในวิธีเวทย์มนตร์เมื่อพิจารณาว่าชื่อนั้นเป็นสมบัติของวัตถุของคุณหรือไม่ และคุณไม่สามารถแก้ปัญหาทั่วไปนี้ได้ด้วยคลาสพื้นฐานเว้นแต่ว่าคลาสทั้งหมดของคุณสืบทอดมาจาก ClassWithProperties เนื่องจาก PHP ขาดการสืบทอดหลายอย่าง

ในทางตรงกันข้ามPythonคลาสสไตล์ใหม่ให้property()ซึ่งจะช่วยให้คุณกำหนดคุณสมบัติทั้งหมดได้อย่างชัดเจน C #มีไวยากรณ์พิเศษ

http://en.wikipedia.org/wiki/Property_(programming)


1
การเรียก property_exists, class_vars หรือ array_key_exists (เช่นการตรวจสอบว่ามีคุณสมบัติจริง ๆ ) เป็นเพียงขั้นตอนหนึ่งเพื่อหลีกเลี่ยงข้อผิดพลาดร้ายแรงขณะใช้งานจริง ฉันไม่แน่ใจว่าถ้าไม่ได้เป็นคนที่น่ารังเกียจเหมือนกับการทำซ้ำในการเขียนโปรแกรม
Davis Peixoto

1
ยุติธรรมพอสมควร แต่ใน Python และ C # การทำซ้ำนี้ไม่จำเป็น ฉันคิดว่านั่นเป็นจุดแข็ง
Emanuel Landeholm

4

ฉันทำการทดลองโดยใช้เวทมนต์ __call ไม่แน่ใจว่าฉันควรโพสต์ไว้หรือไม่ (เพราะคำเตือน "อย่าใช้วิธีวิเศษ" ในคำตอบและความคิดเห็นอื่น ๆ ) แต่ฉันจะทิ้งไว้ที่นี่ .. ในกรณีที่บางคนพบว่ามีประโยชน์


public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = substr($_name, 4);

    if (isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

เพียงเพิ่มวิธีการข้างต้นในชั้นเรียนของคุณตอนนี้คุณสามารถพิมพ์:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_foo(); // return "bar"
$C->get_bom(); // return "bim"

// as setter
$C->set_foo("abc"); // set "abc" as new value of foo
$C->set_bom("zam"); // set "zam" as new value of bom


วิธีนี้คุณสามารถรับ / ตั้งค่าทุกอย่างในชั้นเรียนของคุณถ้ามันมีอยู่หากคุณต้องการมันสำหรับองค์ประกอบเฉพาะบางอย่างคุณสามารถใช้ "รายการที่อนุญาต" เป็นตัวกรอง

ตัวอย่าง:

private $callWhiteList = array(
    "foo" => "foo",
    "fee" => "fee",
    // ...
);

public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = $this->callWhiteList[substr($_name, 4)];

    if (!is_null($varName) && isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

ตอนนี้คุณสามารถรับ / ตั้งค่า "foo" และ "ค่าธรรมเนียม" เท่านั้น
นอกจากนี้คุณยังสามารถใช้ "บัญชีขาว" นั้นเพื่อกำหนดชื่อที่กำหนดเองเพื่อเข้าถึง vars ของคุณ
ตัวอย่างเช่น,

private $callWhiteList = array(
    "myfoo" => "foo",
    "zim" => "bom",
    // ...
);

ด้วยรายการนั้นคุณสามารถพิมพ์:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // private $callWhiteList = array( ... )
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_myfoo(); // return "bar"
$C->get_zim(); // return "bim"

// as setter
$C->set_myfoo("abc"); // set "abc" as new value of foo
$C->set_zim("zam"); // set "zam" as new value of bom

.
.
.
นั่นคือทั้งหมดที่


Doc: __call ()จะถูกเรียกใช้เมื่อเรียกใช้เมธอดที่ไม่สามารถเข้าถึงได้ในบริบทของวัตถุ


ปัญหาเกี่ยวกับการแก้ปัญหา "เวทย์มนตร์" ทั้งหมดนี้ก็คือพวกเขาเพียงแค่ใช้วิธีการเวทย์มนตร์เหล่านี้เพราะพวกเขาอยู่ที่นั่นและพวกเขาก็มีประโยชน์เพราะปัญหาที่ถามมานั้นเป็นวิธีการทั่วไปที่เรียบง่าย เมื่อคุณออกจากปัญหาทั่วไปในระดับนี้แล้วคุณจะพบกับข้อกำหนดเฉพาะที่ไม่สามารถแก้ไขได้ด้วยวิธีเวทย์มนตร์แบบง่าย ๆ แต่จะต้องใช้วิธีเวทย์มนตร์ที่ซับซ้อนมาก - หรือเป็นรายบุคคล
Sven

2

หลังจากอ่านคำแนะนำอื่น ๆ ฉันก็อยากจะบอกว่า:

ในฐานะที่เป็นสามัญกฎที่คุณจะไม่เคยกำหนด setters สำหรับALLคุณสมบัติพิเศษคน "ภายใน" (semaphores ธงภายใน ... ) คุณสมบัติแบบอ่านอย่างเดียวจะไม่มีตัวตั้งค่าดังนั้นคุณสมบัติบางอย่างจะมีตัวตั้งค่าเท่านั้น นั่นคือสิ่งที่ __get () มาเพื่อย่อขนาดโค้ด:

  • กำหนด __get () (ผู้ให้บริการทั่วโลกที่มีมนต์ขลัง) สำหรับคุณสมบัติทั้งหมดที่เหมือนกัน
  • จัดกลุ่มไว้ในอาร์เรย์ดังนั้น:
    • พวกเขาจะแบ่งปันลักษณะทั่วไป: ค่าเงินจะ / อาจมีรูปแบบที่เหมาะสมวันที่ในรูปแบบเฉพาะ (ISO, US, Intl.) ฯลฯ
    • รหัสนั้นสามารถตรวจสอบได้ว่ามีการอ่านคุณสมบัติที่ได้รับอนุญาตเท่านั้นที่มีอยู่โดยใช้วิธีการทางเวทย์มนตร์นี้
    • เมื่อใดก็ตามที่คุณต้องการสร้างคุณสมบัติที่คล้ายกันใหม่ให้ประกาศและเพิ่มชื่อให้กับอาร์เรย์ที่เหมาะสมและเสร็จสิ้น นั่นคือวิธีที่เร็วกว่าการกำหนดผู้ทะเยอทะยานใหม่บางทีอาจมีบางบรรทัดของรหัส REPEATED ซ้ำแล้วซ้ำอีกทั่วรหัสชั้นเรียน

ใช่ เราสามารถเขียนวิธีการส่วนตัวเพื่อทำเช่นนั้น แต่อีกครั้งเราจะประกาศวิธีการมากมาย (++ หน่วยความจำ) ที่สิ้นสุดการเรียกวิธีอื่นเสมอวิธีการเดียวกัน ทำไมไม่เขียนวิธีการเดียวเพื่อควบคุมทั้งหมด ... [อ๋อ! ปุนตั้งใจอย่างแน่นอน! :)]

ผู้ตั้งค่าเวทย์มนตร์ยังสามารถตอบสนองต่อคุณสมบัติเฉพาะเท่านั้นดังนั้นคุณสมบัติประเภทวันที่ทั้งหมดสามารถตรวจสอบกับค่าที่ไม่ถูกต้องในวิธีเดียว หากคุณสมบัติประเภทวันที่มีการระบุไว้ในอาร์เรย์ผู้กำหนดสามารถกำหนดได้อย่างง่ายดาย เป็นเพียงตัวอย่างเท่านั้น มีสถานการณ์มากเกินไป

เกี่ยวกับความสามารถในการอ่าน ... ดี ... นั่นเป็นอีกการถกเถียงกัน: ฉันไม่ชอบที่จะใช้ IDE (ในความเป็นจริงฉันไม่ได้ใช้มันพวกเขามักจะบอกฉัน (และบังคับฉัน) วิธีการ เขียน ... และฉันมีชอบของฉันเกี่ยวกับการเข้ารหัส "ความงาม") ฉันมักจะมีความสอดคล้องกันเกี่ยวกับการตั้งชื่อดังนั้นการใช้ ctags และตัวช่วยอื่นอีกสองอย่างก็เพียงพอแล้วสำหรับฉัน ... อย่างไรก็ตาม: เมื่อผู้ทำเวทมนต์และผู้ที่ทะเยอทะยานเสร็จแล้วฉันก็จะเขียนตัวตั้งอื่นที่เจาะจงเกินไปหรือ "พิเศษ" ไป ทั่วไปในวิธี __set () และนั่นครอบคลุมทั้งหมดที่ฉันต้องการเกี่ยวกับการรับและการตั้งค่าคุณสมบัติ แน่นอน: ไม่มีพื้นดินทั่วไปหรือมีคุณสมบัติบางอย่างที่ไม่คุ้มค่ากับการเข้ารหัสวิธีเวทมนต์และจากนั้นยังมีคู่เซ็ตเตอร์ / ผู้ทะเยอทะยานแบบดั้งเดิมที่เก่าแก่

ภาษาโปรแกรมเป็นเพียง: ภาษาประดิษฐ์ของมนุษย์ ดังนั้นแต่ละคนมีน้ำเสียงหรือสำเนียงไวยากรณ์และรสชาติของตัวเองดังนั้นฉันจะไม่แกล้งเขียนรหัส Ruby หรือ Python โดยใช้ "สำเนียง" เดียวกันมากกว่า Java หรือ C # หรือฉันจะเขียน JavaScript หรือ PHP เพื่อคล้าย Perl หรือ SQL ... ใช้วิธีที่พวกเขาตั้งใจจะใช้


1

โดยทั่วไปแล้ววิธีแรกนั้นเป็นที่นิยมมากกว่าเพราะผู้ที่มีความรู้ด้านการเขียนโปรแกรมมาก่อนสามารถเปลี่ยนไปใช้ PHP และทำงานในรูปแบบเชิงวัตถุได้อย่างง่ายดาย วิธีแรกเป็นสากลมากขึ้น คำแนะนำของฉันคือยึดสิ่งที่พยายามและเป็นจริงในหลายภาษา จากนั้นเมื่อใดและถ้าคุณใช้ภาษาอื่นคุณก็พร้อมที่จะทำบางสิ่งให้สำเร็จ ( แทนที่จะใช้เวลาในการปรับแต่งวงล้อ )


0

มีหลายวิธีในการสร้างซอร์สโค้ดใน netbeans-Convention นี่เป็นสิ่งที่ดี มันทำให้คิดว่าง่ายกว่า === FALSE เพียงแค่ใช้ประเพณีโดยเฉพาะอย่างยิ่งถ้าคุณไม่แน่ใจว่าหนึ่งในคุณสมบัติที่ควรจะถูกห่อหุ้มและที่หนึ่งไม่ ฉันรู้ว่ามันเป็นรหัส boi .... pla ... แต่สำหรับการดีบั๊ก - งานและอีกหลายคนคิดว่ามันเป็นวิธีที่ดีกว่าชัดเจน อย่าใช้เวลามากกับศิลปะมากมายวิธีการสร้างผู้ได้รับและผู้ตั้งง่าย คุณไม่สามารถใช้รูปแบบการออกแบบบางอย่างเช่นกฎ demeter ได้เช่นกันหากคุณใช้เวทมนต์ ในสถานการณ์เฉพาะคุณสามารถใช้ magic_calls หรือสำหรับโซลูชันขนาดเล็กรวดเร็วและชัดเจน แน่นอนว่าคุณสามารถแก้ปัญหาสำหรับผู้ออกแบบด้วยวิธีนี้ได้เช่นกัน แต่ทำไมต้องทำให้คุณมีชีวิตที่ยากขึ้น


0

การตรวจสอบความถูกต้อง + การจัดรูปแบบ / ค่าที่ได้รับ

ตัวตั้งค่าช่วยให้คุณสามารถตรวจสอบความถูกต้องของข้อมูลและตัวรับสัญญาณช่วยให้คุณสามารถจัดรูปแบบหรือรับข้อมูลได้ วัตถุช่วยให้คุณสามารถแค็ปซูลข้อมูลและการตรวจสอบและรหัสการจัดรูปแบบเป็นแพคเกจเรียบร้อยที่ส่งเสริม DRY

ตัวอย่างเช่นพิจารณาคลาสง่าย ๆ ดังต่อไปนี้ที่มีวันเกิด

class BirthDate {

    private $birth_date;

    public function getBirthDate($format='Y-m-d') {
        //format $birth_date ...
        //$birth_date = ...
        return $birth_date;
    }

    public function setBirthDate($birth_date) {                   
        //if($birth_date is not valid) throw an exception ...          
        $this->birth_date = $birth_date;
    }

    public function getAge() {
        //calculate age ...
        return $age;
    }

    public function getDaysUntilBirthday() {
        //calculate days until birth days
        return $days;
    }
}

คุณจะต้องตรวจสอบว่ามีการตั้งค่า

  • วันที่ที่ถูกต้อง
  • ไม่ใช่ในอนาคต

และคุณไม่ต้องการทำการตรวจสอบนี้กับแอปพลิเคชันของคุณ (หรือมากกว่าแอพพลิเคชั่นหลายตัวสำหรับเรื่องนั้น) แต่จะทำให้ตัวแปรสมาชิกได้รับการปกป้องหรือเป็นเรื่องส่วนตัวได้ง่ายขึ้น (เพื่อให้ตัวตั้งค่าเป็นจุดเข้าใช้งานเท่านั้น) และตรวจสอบความถูกต้องในตัวตั้งค่าเพราะคุณจะรู้ว่าวัตถุนั้นมีวันเดือนปีเกิดที่ถูกต้อง แอปพลิเคชันวัตถุมาจากและหากคุณต้องการเพิ่มการตรวจสอบเพิ่มเติมจากนั้นคุณสามารถเพิ่มได้ในที่เดียว

คุณอาจต้องการเพิ่มตัวจัดรูปแบบหลายตัวที่ทำงานกับตัวแปรสมาชิกเดียวกันgetAge()และgetDaysUntilBirthday()และคุณอาจต้องการบังคับใช้รูปแบบที่กำหนดค่าได้getBirthDate()ขึ้นอยู่กับโลแคล ดังนั้นผมจึงชอบอย่างต่อเนื่องในการเข้าถึงค่าผ่านทาง getters เมื่อเทียบกับการผสมกับ$date->getAge()$date->birth_date

getters และ setters ยังมีประโยชน์เมื่อคุณขยายวัตถุ ตัวอย่างเช่นสมมติว่าแอปพลิเคชันของคุณจำเป็นต้องอนุญาตให้มีวันเดือนปีเกิดมากกว่า 150 ปีในบางแห่ง แต่ไม่ใช่ในประเทศอื่น ๆ วิธีหนึ่งในการแก้ปัญหาโดยไม่ต้องทำซ้ำรหัสใด ๆ ก็คือการขยายBirthDateวัตถุและทำให้การตรวจสอบเพิ่มเติมใน setter

class LivingBirthDate extends BirthDate {

    public function setBirthDate($birth_date) {
        //if $birth_date is greater than 150 years throw an exception
        //else pass to parent's setter
        return parent::setBirthDate($birth_date);
    }
}

อย่างไรก็ตามหลายครั้งคุณต้องตรวจสอบคุณสมบัติด้วยกัน ฉันคิดว่าการอนุญาต "setters" หมายความว่าคุณไม่ได้ถ่ายบริบท ควรทำการตรวจสอบความถูกต้องตามบริบท นอกจากนี้คุณจะถูกบังคับให้ตรวจสอบการตั้งค่าสถานะ "isValid" บางอย่างในทุกวิธีที่คุณมี (และตรวจสอบความถูกต้องหากเป็นเท็จ) ตามที่กล่าวมาผู้ตั้งค่าจะให้วิธีที่มีประโยชน์ในการพิมพ์คำใบ้เช่นเมื่อคุณมีคุณสมบัติที่คุณต้องการให้เป็นวัตถุที่มีมูลค่า (เช่นเงิน)
prograhammer

ฉันไม่เข้าใจสิ่งที่คุณหมายถึงโดยถูกบังคับให้ตรวจสอบการตั้งค่าสถานะ "isValid"? หากวิธีเดียวในการตั้งค่าคือผ่านตัวตั้งค่าที่ทำการตรวจสอบความถูกต้องคุณจะทราบว่าข้อมูลนั้นถูกต้องตามความจริงที่ตั้งค่าไว้เรียบร้อยแล้ว หากคุณต้องการตรวจสอบคุณสมบัติด้วยกันคุณสามารถเขียนวิธีการตรวจสอบความถูกต้องทั่วไปที่ setters ของคุณสมบัติเหล่านั้นเรียกใช้
FuzzyTree

สมมติว่าคุณมีระดับพนักงานที่มีและsetHired setHireDateไม่ถูกต้องที่จะให้คนกำหนดวันจ้างโดยไม่ตั้งค่าพนักงานเป็นลูกจ้าง แต่ไม่มีทางที่คุณจะบังคับใช้สิ่งนี้ หากคุณบังคับใช้ในหนึ่งใน setters เหล่านี้กว่าที่คุณจะบังคับให้ลำดับของ "การตั้งค่า" และที่ต้องมีการอ่านรหัสเพิ่มเติมจากนักพัฒนาที่จะรู้ จากนั้นเมื่อคุณไปทำวิธีการเช่น$employee->promote($newPosition);คุณต้องตรวจสอบการตั้งค่าสถานะเพื่อดูว่าการตรวจสอบได้ทำหรือคิดว่ามันไม่ได้ทำและทำมันอีกครั้ง (ซ้ำซ้อน)
prograhammer

ให้จับภาพการโต้ตอบแทน บางที$employee->updateWorkStatus($hired, $hireDate);หรือถ้าสูง$employee->adminUpdate(\Employee\AdminUpdateDTO $dto);ขึ้น ตอนนี้คุณสามารถตรวจสอบความถูกต้องในบริบทที่คุณต้องการและตัดสินใจได้ว่าต้องการการตรวจสอบพิเศษใด ๆ เพิ่มเติมหรือไม่
prograhammer

updateWorkStatus นั้นเป็นฟังก์ชั่น setter ที่ตั้งค่าเป็น 2 แทนค่า 1 แต่แนวคิดจะเหมือนกัน นั่นเป็นวิธีหนึ่งในการทำ แต่คุณยังสามารถใส่การตรวจสอบความถูกต้องตามบริบทในวิธีการทั่วไปที่จะทำงานก็ต่อเมื่อมีการตั้งค่าคุณสมบัติทั้งหมดที่ต้องตรวจสอบความถูกต้องร่วมกันเช่นส่วนบริบทของการตรวจสอบความถูกต้อง ถ้าทั้งคู่ที่ได้รับการว่าจ้างและผู้ที่ได้รับการว่าจ้างวันที่จริง
FuzzyTree

0

โพสต์นี้ไม่เฉพาะเจาะจงเกี่ยวกับ__getและ__setค่อนข้าง__callจะเป็นความคิดเดียวกันยกเว้นวิธีการโทร ตามกฎแล้วฉันอยู่ห่างจากวิธีการทางเวทย์มนตร์ทุกประเภทที่อนุญาตให้มีการโอเวอร์โหลดด้วยเหตุผลที่ระบุไว้ในความคิดเห็นและโพสต์อย่างไรก็ตามเมื่อเร็ว ๆ นี้ฉันพบกับ API ของบุคคลที่สามที่ฉันใช้ซึ่งใช้บริการและ SUB-SERVICE :

http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234

ส่วนที่สำคัญคือ API นี้มีทุกอย่างเหมือนกันยกเว้นการกระทำย่อยในกรณีdoActionOneนี้ แนวคิดก็คือผู้พัฒนา (ตัวฉันเองและคนอื่น ๆ ที่ใช้คลาสนี้) สามารถเรียกใช้บริการย่อยโดยใช้ชื่อแทนสิ่งที่ต้องการ:

$myClass->doAction(array('service'=>'doActionOne','args'=>$args));

ฉันสามารถทำแทน:

 $myClass->doActionOne($args);

หากต้องการ hardcode นี่เป็นการทำซ้ำจำนวนมาก (ตัวอย่างนี้มีลักษณะคล้ายกับโค้ดอย่างหลวม ๆ ):

public function doActionOne($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionTwo($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionThree($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

protected function executeCoreCall($service)
    {
        $cURL = new \cURL();
        return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
                    ->getResponse();
    }

แต่ด้วยวิธีมหัศจรรย์ของ__call()ฉันสามารถเข้าถึงบริการทั้งหมดด้วยวิธีการแบบไดนามิก:

public function __call($name, $arguments)
    {
        $this->args     =   $arguments;
        $this->response =   $this->executeCoreCall("APIService.{$name}");   
        return $this;
    }

ประโยชน์ของการโทรแบบไดนามิกสำหรับการส่งคืนข้อมูลคือถ้าผู้ขายเพิ่มบริการย่อยอื่นฉันไม่ต้องเพิ่มวิธีอื่นในชั้นเรียนหรือสร้างคลาสเพิ่มเติม ฯลฯ ฉันไม่แน่ใจว่าสิ่งนี้มีประโยชน์สำหรับ ทุกคน แต่ฉันคิดฉันจะแสดงตัวอย่างกรณีที่__set, __get, __callฯลฯ อาจเป็นตัวเลือกสำหรับการพิจารณาตั้งแต่ฟังก์ชั่นหลักคือการกลับมาของข้อมูล


แก้ไข:

บังเอิญฉันเห็นสิ่งนี้สองสามวันหลังจากโพสต์ซึ่งสรุปสถานการณ์ของฉัน ไม่ใช่ API ที่ฉันอ้างถึง แต่การใช้วิธีการเหมือนกัน:

ฉันใช้ API อย่างถูกต้องหรือไม่


-2

อัปเดต: อย่าใช้คำตอบนี้เพราะนี่เป็นรหัสใบ้ที่ฉันพบในขณะที่เรียนรู้ เพียงใช้ตัวทะลุธรรมดาและตัวเซ็ตมันจะดีกว่ามาก


ฉันมักจะใช้ชื่อตัวแปรนั้นเป็นชื่อฟังก์ชั่นและเพิ่มพารามิเตอร์ทางเลือกให้กับฟังก์ชั่นนั้นดังนั้นเมื่อพารามิเตอร์ตัวเลือกเต็มไปด้วยผู้เรียกจากนั้นตั้งค่าเป็นคุณสมบัติและส่งกลับ $ this object (chaining) แล้วเมื่อพารามิเตอร์ทางเลือกนั้นไม่ได้ระบุ ผู้โทรฉันแค่ส่งคืนคุณสมบัติไปยังผู้โทร

ตัวอย่างของฉัน:

class Model
{
     private $propOne;
     private $propTwo;

     public function propOne($propVal = '')
     {
          if ($propVal === '') {
              return $this->propOne;
          } else {
              $this->propOne = $propVal;
              return $this;
          }
     }

     public function propTwo($propVal = '')
     {
          if ($propVal === '') {
              return $this->propTwo;
          } else {
              $this->propTwo = $propVal;
              return $this;
          }
     }
}

ตอนนี้คำถามยังคงอยู่: คุณจะตั้งค่าคุณสมบัติเป็นสตริงว่างได้อย่างไร และคุณตรวจพบได้อย่างไรว่าการตั้งค่าคุณสมบัติเป็นสตริงว่างเปล่าล้มเหลวและทำงานเป็น getter จริง ๆ ? แค่คิดเกี่ยวกับรูปแบบ HTML ที่ส่งเขตข้อมูลที่ว่างเปล่าเป็นสตริง ... และไม่ใช่: การใช้ค่าอื่นเช่น NULL เนื่องจากค่าเริ่มต้นไม่สามารถแก้ปัญหาได้
Sven
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.