在php中获取设置属性

问题描述 投票:0回答:10

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

public int ID { get; set; }

在 php 中相当于什么?

谢谢。

php get set
10个回答
34
投票

没有,尽管有一些在未来版本中实施的建议。 不幸的是,现在您需要手动声明所有 getter 和 setter。

private $ID;

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

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

对于一些魔法(PHP喜欢魔法),你可以查找

__set
__get
魔法方法。

示例

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

9
投票

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

在我的家长班上:

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);
}
}

6
投票

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


5
投票

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

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

1
投票
private $ID;

public function getsetID($value = NULL)
{
    if ($value === NULL) {
        return $this->ID;
    } else {
        $this->ID = $value;
    }
}

1
投票

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

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

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

这是特征本身的代码:

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; });

0
投票

我喜欢使用这种模式:

class foo 
{
    //just add p as prefix to be different than method name.
    protected $pData;
    
    public funtion __construct() {} 
    public funtion __destruct() {}
    public funtion __clone() {}

    public function Data($value == "") 
    {
        if ($value != "") {
            $this->pData = $value;
        }
        return $this->pData;
    }
}
$myVar = new foo();
//for SET
$myVar->Data("A Value");
//for GET
$item = $myVar->Data();


0
投票
class MyClass
{
    private $name = null;

    public function __construct($name = null)
    {
        $this->name = $name;
    }

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

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

0
投票

从 2025 年的 PHP 8.4 开始,我们终于能够使用所谓的属性挂钩 (https://wiki.php.net/rfc/property-hooks)。

与 C# 代码等效的代码如下所示:

public int $ID {
    get {
        return $this->ID;
    }
    set(int $value) {
        $this->ID = $value;
    }
}

可以使用箭头表示法,如下所示:

public int $ID {
    get => $this->ID;
    set => $value
}

如果您愿意,您可以省略 getter 或 setter,然后它将被 PHP 的默认读/写行为替换。显然,这个简单的例子与:

public int $ID;

还可以创建虚拟属性。他们不允许有二传手:

public int $ID {
    get => 12345;
}

注意:始终确保 getter 返回的类型和 setter 接收的类型与属性的类型匹配。


-5
投票

这是 PHP ;你不需要设置

class MyClass {
  public $ID;
}

$object = new MyClass();
$object->ID = 'foo';
echo $object->ID;

会工作

© www.soinside.com 2019 - 2024. All rights reserved.