【问题标题】:get set properties in php在php中获取设置属性
【发布时间】:2012-03-08 09:15:11
【问题描述】:

我来自 C# 环境,我开始在学校学习 PHP。 我习惯于像这样在 C# 中设置我的属性。

public int ID { get; set; }

php中的this相当于什么?

谢谢。

【问题讨论】:

    标签: php get set


    【解决方案1】:

    没有,尽管在未来的版本中有some proposals for implementing。 不幸的是,现在您需要手动声明所有 getter 和 setter。

    private $ID;
    
    public function setID($ID) {
      $this->ID = $ID;
    }
    
    public function getID() {
      return $this->ID;
    }
    

    对于一些魔法(PHP 喜欢魔法),您可以查找 __set__get magic methods.

    例子

    class MyClass {
    
      private $ID;
    
      private function setID($ID) {
        $this->ID = $ID;
      }
    
      private function getID() {
        return $this->ID;
      }
    
    
      public function __set($name,$value) {
        switch($name) { //this is kind of silly example, bt shows the idea
          case 'ID': 
            return $this->setID($value);
        }
      }
    
      public function __get($name) {
        switch($name) {
          case 'ID': 
            return $this->getID();
        }
      }
    
    }
    
    
    $object = new MyClass();
    $object->ID = 'foo'; //setID('foo') will be called
    

    【讨论】:

      【解决方案2】:

      Mchi 是对的,但是还有另一种方法是使用单个函数来做到这一点

          private $ID;
      
      public function ID( $value = "" )
      
      {
      
          if( empty( $value ) )
      
              return $this->ID;
      
          else
      
              $this->ID = $value;
      
      }
      

      但是,是的,这种方法与您在 c# 中所做的几乎是一致的。但这只是一种选择

      或者尝试在你的班级中使用 php 的 __set 和 __get 来获得更多信息

      http://php.net/manual/en/language.oop5.overloading.php

      【讨论】:

      • 虽然是一种有趣的方法,但我看到了一些缺点:首先,函数的名称并不暗示它的作用(其中没有动词),其次如果我特别想设置一个空怎么办ID 的价值? $class->ID(4); $class->ID(''); echo $class->ID(); 将打印 4 ...
      • @cassy。这就是为什么我说它是另一种选择。在 c# 中,即使你可以拥有它们,你也没有 setX 或 getX,所以我想我最好展示一些可以与 c# 保持一致的东西:) 你列出的示例以突出上述方法的缺点。我支持你,但你可以做很多事情来让它按照你想要的方式进行。所以我的想法只是展示一种方法而不是解决方案。
      • 请原谅死灵。但是现在使用 PHP 的可变参数 ... 运算符可以更有效地完成此操作。 function foo(...$args) { if (empty($args)) { return $this->foo; } else { $this->foo = $args[0]; } }
      【解决方案3】:
      private $ID;
      
      public function getsetID($value = NULL)
      {
          if ($value === NULL) {
              return $this->ID;
          } else {
              $this->ID = $value;
          }
      }
      

      【讨论】:

      • 如何设置ID为空?
      • @MaximColesnic, if (func_num_args() === 0) 可以用于此。
      【解决方案4】:

      另一个使用变量函数名的例子

      class MyClass {
      
        private $ID;
        protected $ID2;
      
        private function setID($ID) {
          $this->ID = $ID;
        }
        private function getID() {
          return $this->ID;
        }
        private function setID2($ID2) {
          $this->ID2 = $ID2;
        }
      
        private function getID2() {
          return $this->ID2;
        }
        public function __set($name,$value) {
          $functionname='set'.$name;
          return $this->$functionname($value);
        }
        public function __get($name) {
          $functionname='get'.$name;
          return $this->$functionname();
        }
      
      }
      
      
      $object = new MyClass();
      $object->ID = 'foo'; //setID('foo') will be called
      $object->ID2 = 'bar'; //setID2('bar') will be called
      

      【讨论】:

        【解决方案5】:

        感谢大家的回答。它帮助我创造了这样的东西:

        在我的父类中:

        public function __get($name){
        
            if (ObjectHelper::existsMethod($this,$name)){
                return $this->$name();
            }
        
            return null;
        }
        
        public function __set($name, $value){
        
            if (ObjectHelper::existsMethod($this,$name))
                $this->$name($value);
        }
        

        ObjectHelper::existsMethod 是一种仅检查给定受保护方法是否存在的方法。

        private $_propertyName = null;
        
        protected function PropertyName($value = ""){
        
            if (empty($value)) // getter
            {
                if ($this-> _propertyName != null)
                    return $this->_propertyName;
            }
            else // setter
            {
                $this-> _propertyName = $value;
            }
        
            return null;
        }
        

        所以我可以在任何课程中使用这样的东西:

        $class = new Class();
        $class->PropertyName = "test";
        echo $class->PropertyName;
        

        我受到 C# 的启发 :)

        各位,你们怎么看?

        这是我的 ObjectHelper,如果有人想使用它:

        namespace Helpers;
        
        use ReflectionMethod;
        
        class ObjectHelper {
        
        public static function existsMethod($obj, $methodName){
        
            $methods = self::getMethods($obj);
        
            $neededObject = array_filter(
                $methods,
                function ($e) use($methodName) {
                    return $e->Name == $methodName;
                 }
            );
        
            if (is_array($neededObject))
                return true;
        
            return false;
        }
        
        public static function getMethods($obj){
        
            $var = new \ReflectionClass($obj);
        
            return $var->getMethods(ReflectionMethod::IS_PROTECTED);
        }
        }
        

        【讨论】:

        • 我想使用这样的东西来减少 PHP get/set 使用的繁琐样板。我可以建议对您的方法进行一些改进吗? 1) 为方法添加“getPropertyName”和“setPropertyName”前缀的命名约定要求,以避免调用者能够将所有方法作为属性调用,这会导致混淆(或添加一个const属性列表)。跨度>
        • 2) 使用 Trait 比使用父类要容易得多(在您编写此代码时可能不可用)。
        • 3) 继续扩展帮助器以通过属性命名约定和动态 $propertyName 执行实际的 get/set 样板。这对我来说将是最有价值的部分。由于每个属性的额外重复代码量,我从来没有为 PHP 的 get/set 烦恼。
        • 4) 收紧“get”案例的空检查。正如其他人所指出的,您需要将属性设置为空值,当然是 0 和“”和 []。 Null 似乎是最好的,尽管它仍然排除了将属性实际设置为 null 的可能性。除了另一种方法或不执行 getset 单一功能之外,我看不到绕过该 ATM 的简单方法。
        • 一旦一切就绪,我想性能基准可能不会出错!考虑到设置属性是一个如此低级的活动,性能对于某些对象或其用途可能至关重要。毕竟,硬编码(或生成)的样板文件可能效率更高。
        【解决方案6】:

        我知道我在这个问题上迟到了,但我自己也有同样的问题/想法。作为一名使用 PHP 的 C# 开发人员,当工作需要时,我希望有一种简单的方法来创建我在 C# 中能够做到的属性。

        今天下午我起草了一份初稿,它允许您创建支持字段并指定它们的访问器,或者拥有没有支持字段的纯访问器。随着代码的发展,我将更新我的答案,并在我将其作为可以作为 composer 包导入的状态时提供一个链接。

        为简单起见,我将功能创建为 PHP 特征,因此您可以将其放入所需的任何类中,而不必扩展基类。最终,我希望扩展此功能,以区分对属性的外部公共调用和受保护/私有调用。

        这是 trait 本身的代码:

        trait PropertyAccessorTrait
        {
            private static $__propertyAccessors = [];
        
            /* @property string $__propertyPrefix */
        
            public function __get($name)
            {
                $this->__populatePropertyAcessors($name);
        
                return $this->__performGet($name);
            }
        
            public function __set($name, $value)
            {
                $this->__populatePropertyAcessors($name);
        
                $this->__performSet($name, $value);
            }
        
            public function __isset($name)
            {
                // TODO: Implement __isset() method.
            }
        
            public function __unset($name)
            {
                // TODO: Implement __unset() method.
            }
        
            protected function __getBackingFieldName($name)
            {
                if (property_exists(self::class, '__propertyPrefix')) {
                    $prefix = $this->__propertyPrefix;
                } else {
                    $prefix = '';
                }
        
                return $prefix . $name;
            }
        
            protected function __canget($name)
            {
                $accessors = $this->__getPropertyAccessors($name);
        
                return $accessors !== null && isset($accessors['get']);
            }
        
            protected function __canset($name)
            {
                $accessors = $this->__getPropertyAccessors($name);
        
                return $accessors !== null && isset($accessors['set']);
            }
        
            protected function __performGet($name)
            {
                if (!$this->__canget($name)) {
                    throw new \Exception('Getter not allowed for property: ' . $name);
                }
        
                $accessors = $this->__getPropertyAccessors($name)['get'];
        
                /* @var \ReflectionMethod $method */
                $method = $accessors['method'];
        
                if (!empty($method)) {
                    return $method->invoke($this);
                }
        
                return $this->{$this->__getBackingFieldName($name)};
            }
        
            protected function __performSet($name, $value)
            {
                if (!$this->__canset($name)) {
                    throw new \Exception('Setter not allowed for property: ' . $name);
                }
        
                $accessors = $this->__getPropertyAccessors($name)['set'];
        
                /* @var \ReflectionMethod $method */
                $method = $accessors['method'];
        
                if (!empty($method)) {
                    return $method->invoke($this, $value);
                }
        
                $this->{$this->__getBackingFieldName($name)} = $value;
            }
        
            protected function __getPropertyAccessors($name)
            {
                return isset(self::$__propertyAccessors[$name])
                    ? self::$__propertyAccessors[$name]
                    : null
                    ;
            }
        
            protected function __getAccessorsFromDocBlock($docblock)
            {
                $accessors = [];
        
                if (!empty(trim($docblock))) {
                    $doclines = null;
        
                    if (!empty($docblock)) {
                        $doclines = explode("\n", $docblock);
                    }
        
                    if (!empty($doclines)) {
                        foreach ($doclines as $line) {
                            if (preg_match('/@(get|set)\\s+(public|private|protected)/', $line, $matches)) {
                                $accessors[$matches[1]]['visibility'] = $matches[2];
                            }
                        }
                    }
                }
        
                return $accessors;
            }
        
            protected function __populatePropertyAcessors($name)
            {
                if ($this->__getPropertyAccessors($name) !== null) return;
        
                try {
                    $property = new \ReflectionProperty(self::class, $this->__getBackingFieldName($name));
                } catch (\ReflectionException $ex) {
                    $property = null;
                }
        
                $accessors = [];
        
                if ($property != null) {
                    $accessors = $this->__getAccessorsFromDocBlock($property->getDocComment());
                }
        
                try {
                    $methodName = 'get' . ucfirst($name);
                    $method = new \ReflectionMethod(self::class, $methodName);
                    $method->setAccessible(true);
                    $accessors = array_merge($accessors, $this->__getAccessorsFromDocBlock($method->getDocComment()));
                } catch (\ReflectionException $ex) {
                    $method = null;
                }
        
        
                if ($method !== null || isset($accessors['get'])) {
                    $accessors['get']['method'] = $method;
                }
        
                try {
                    $methodName = 'set' . ucfirst($name);
                    $method = new \ReflectionMethod(self::class, $methodName);
                    $method->setAccessible(true);
                    $accessors = array_merge($accessors, $this->__getAccessorsFromDocBlock($method->getDocComment()));
                } catch (\ReflectionException $ex) {
                    $method = null;
                }
        
                if ($method !== null || isset($accessors['set'])) {
                    $accessors['set']['method'] = $method;
                }
        
                self::$__propertyAccessors[$name] = $accessors;
            }
        }
        

        这是我使用 Codeception 格式创建的快速单元测试:

        <?php
        
        class PropertyAssesorTraitTestClass
        {
            use PropertyAccessorTrait;
        
            private $__propertyPrefix = '_';
        
            /**
             * @get public
             * @set public
             */
            private $_integer = 1;
        
            /**
             * @get public
             */
            private $_getonly = 100;
        
            /**
             * @set public
             */
            private $_setonly;
        
            private $_customDoubler;
        
            private function getCustomDoubler()
            {
                return $this->_customDoubler * 2;
            }
        
            private function setCustomDoubler($value)
            {
                $this->_customDoubler = $value * 2;
            }
        
            public $publicField = 1234;
        
            /**
             * @return int
             * @get public
             */
            private function getPureAccessor()
            {
                return $this->publicField;
            }
        
            /**
             * @param $value
             * @set public
             */
            private function setPureAccessor($value)
            {
                $this->publicField = $value;
            }
        
            private $_purePrivate = 256;
        }
        
        $I = new UnitTester($scenario);
        $I->wantTo('Ensure properties are accessed correctly');
        
        $instance = new PropertyAssesorTraitTestClass();
        $I->assertSame(1, $instance->integer);
        
        $instance->integer = 2;
        $I->assertSame(2, $instance->integer);
        
        $instance->integer = $instance->integer + 1;
        $I->assertSame(3, $instance->integer);
        
        $instance->integer++;
        $I->assertSame(4, $instance->integer);
        
        $I->assertSame(100, $instance->getonly);
        $I->expectException('Exception', function () use ($instance) { $instance->getonly = 50; });
        
        $instance->setonly = 50;
        $I->expectException('Exception', function () use ($instance) { $a = $instance->setonly; });
        
        $instance->customDoubler = 100;
        $I->assertSame(400, $instance->customDoubler);
        
        $I->assertSame(1234, $instance->publicField);
        $instance->pureAccessor = 1000;
        $I->assertSame(1000, $instance->publicField);
        $instance->publicField = 1234;
        $I->assertSame(1234, $instance->publicField);
        $I->assertSame(1234, $instance->pureAccessor);
        
        $I->expectException('Exception', function () use ($instance) { return $instance->purePrivate; });
        

        【讨论】:

          【解决方案7】:

          这是 PHP ;你不需要设置

          class MyClass {
            public $ID;
          }
          
          $object = new MyClass();
          $object->ID = 'foo';
          echo $object->ID;
          

          会起作用

          【讨论】:

            猜你喜欢
            • 2011-07-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-18
            • 1970-01-01
            相关资源
            最近更新 更多