我来自C#环境,我在学校开始学习PHP。 我习惯在 C# 中像这样设置属性。
public int ID { get; set; }
在 php 中相当于什么?
谢谢。
没有,尽管有一些在未来版本中实施的建议。 不幸的是,现在您需要手动声明所有 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
谢谢大家的回答。它帮助我创建了这样的东西:
在我的家长班上:
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);
}
}
Mchi是正确的,但是还有另一种方法可以使用单个函数
private $ID;
public function ID( $value = "" )
{
if( empty( $value ) )
return $this->ID;
else
$this->ID = $value;
}
但是,是的,这种方法与您在 C# 中所做的非常一致。但这只是一个替代方案
或者尝试在你的类中使用 php 的 __set 和 __get 更多信息在这里
另一个使用变量函数名称的示例
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
private $ID;
public function getsetID($value = NULL)
{
if ($value === NULL) {
return $this->ID;
} else {
$this->ID = $value;
}
}
我知道我在这个问题上有点晚了,但我自己也有同样的问题/想法。 作为一名使用 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; });
我喜欢使用这种模式:
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();
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;
}
}
从 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 接收的类型与属性的类型匹配。
这是 PHP ;你不需要设置
class MyClass {
public $ID;
}
$object = new MyClass();
$object->ID = 'foo';
echo $object->ID;
会工作