为什么__set()和__get()私有了,还是可以执行?

本文详细解析了PHP中__set()和__get()方法的私有化特性,以及类内部如何灵活调用封装的方法,同时探讨了这些内置方法在实际编程中的应用与意义。

    //__set()和__get()方法私有了,还是可以执行,
    //是因为目前程序的指针已经在类内了。而类内可以执行封装的方法
    //类内执行私有方法,不会出现任何错误。

    //__set()和__get()其实就是php内置的方法

class Computer {


        private $_name;
        private $_model;
        private $_cpu;
        

        //用private私有__set()和__get()方法,防止外部直接访问


        private function __set($_key,$_value) {
            $this->$_key = $_value;
        }
        private function __get($_key) {
            return $this->$_key;
        }
    }

    $computer = new Computer();
    $computer->_name = '联想';
    $computer->_cpu = '四核';
    $computer->_model = 'i7';

    echo $computer->_name;
    echo $computer->_cpu;

    echo $computer->_model;



<think>根据用户的问题,我们需要在GDScript中为布尔变量`can_attack`添加gettersetter方法。在GDScript中,我们可以使用`setget`关键字来实现属性的gettersetter。 步骤: 1. 声明一个成员变量,例如`_can_attack`(通常加下划线表示私有,但GDScript中并没有真正的私有,只是一种约定)。 2. 然后使用`setget`关键字来指定settergetter函数。 但是注意:在GDScript中,我们可以直接为变量定义settergetter,而不需要定义两个单独的函数(除我们需要额外的逻辑)。基本语法如下: ```gdscript var variable = default_value setget setter_function, getter_function ``` 然而,我们也可以不定义getter函数,只定义setter,或者两者都定义。如果我们不指定getter,那么默认直接返回变量的值。 对于布尔变量`can_attack`,我们可以这样: 假设我们有一个私有变量`_can_attack`,然后我们通过属性`can_attack`来访问,并为其添加settergetter。 但是,我们也可以直接为同一个变量添加settergetter,而不需要两个变量。不过,为了避免循环调用,我们通常会在setter中设置一个后备变量。 例如: ```gdscript var _can_attack: bool = true var can_attack: bool: get: return _can_attack set(value): _can_attack = value # 这里可以添加一些额外的逻辑,比如当设置值的时候触发一些操作 ``` 在GDScript 3.0及以上版本中,我们可以使用更简洁的语法(使用`setget`关键字)或者使用属性语法(如上所示)。但是,属性语法(使用`var <name>: <type>:`后面跟`get``set`)是GDScript 3.0之后推荐的方式。 因此,我们可以这样写: 方案1(使用属性语法): ```gdscript var _can_attack: bool = true var can_attack: bool: get: return _can_attack set(value): # 在设置值之前,我们可以做一些检查或处理 if value != _can_attack: _can_attack = value # 做一些额外的操作,比如发出信号等 ``` 方案2(使用setget关键字): ```gdscript var _can_attack: bool = true var can_attack: bool setget set_can_attack, get_can_attack func set_can_attack(value: bool) -> void: if value != _can_attack: _can_attack = value # 做一些额外的操作 func get_can_attack() -> bool: return _can_attack ``` 两种方式都可以,但是属性语法更现代,也更清晰。 用户可能希望当`can_attack`被设置时,执行一些特定的逻辑(比如更新UI、触发状态变化等)。所以我们在setter中添加了条件判断,只有值改变时才执行额外操作。 注意:在GDScript中,如果不需要额外的逻辑,我们也可以不写gettersetter,直接使用公共变量。但是当需要封装时,使用gettersetter是很好的实践。 示例:在设置`can_attack`为false时,播放一个冷却动画,然后在动画结束后再将其设置为true。 我们可以这样: ```gdscript var _can_attack: bool = true var can_attack: bool: get: return _can_attack set(value): if _can_attack == value: return _can_attack = value if !value: # 开始冷却,然后等待一段时间(比如播放一个冷却动画) $AnimationPlayer.play("cooldown") else: # 可能不需要做任何事,或者更新状态 pass # 然后在动画播放结束的信号中,将can_attack设置为true func _on_animation_player_animation_finished(anim_name: StringName): if anim_name == "cooldown": can_attack = true ``` 这样,当外部设置`can_attack`为false时,就会播放冷却动画,动画结束后再设置为true。 注意:在setter中,我们避免在值没有变化时做不必要的操作,并且避免循环设置(比如在setter中设置自身导致无限递归)。 因此,回答用户的问题:在GDScript中,我们可以使用属性语法(带getset)来为布尔变量`can_attack`添加gettersetter方法。 下面是一个完整的代码示例: ```gdscript extends Node # 私有变量,通过属性访问 var _can_attack: bool = true # 公共属性,带settergetter var can_attack: bool: get: return _can_attack set(value): # 如果值没有变化,直接返回 if _can_attack == value: return # 更新值 _can_attack = value # 这里可以添加设置值后的额外逻辑 if not _can_attack: print("进入冷却状态") # 触发冷却动画或计时器 else: print("冷却结束,可以攻击") # 示例:在某个攻击动作后调用 func attack(): if can_attack: # 执行攻击 print("执行攻击") # 攻击后进入冷却 can_attack = false else: print("攻击冷却中,无法攻击") # 假设我们有一个计时器或动画结束后调用此函数来结束冷却 func _on_cooldown_finished(): can_attack = true ``` 这样,我们就为`can_attack`添加了gettersetter,并在setter中加入了额外的逻辑。 注意:在GDScript中,我们通常使用下划线前缀来表示私有变量,但这不是强制的,只是约定。 另外,如果不需要额外的逻辑,我们可以简化为: ```gdscript var can_attack: bool = true setget set_can_attack func set_can_attack(value: bool): can_attack = value # 注意:这里会递归调用set_can_attack,导致栈溢出 ``` 所以,为了避免递归,我们必须使用一个后备存储变量(如`_can_attack`)。因此,使用属性语法(带getset)更清晰,且不容易出错。 因此,推荐使用属性语法。 相关问题: 1. GDScript中如何定义私有变量? 2. 在setter方法中如何避免无限递归? 3. 如何通过gettersetter实现只读属性? 4. GDScript中如何为其他类型(如int、String)添加gettersetter?</think>在 GDScript 中为布尔变量 `can_attack` 添加 getter setter 方法,可以通过以下方式实现封装: ### 完整实现方案 ```gdscript var _can_attack: bool = true # 私有变量(约定以下划线开头) # Getter 方法 func can_attack() -> bool: return _can_attack # Setter 方法 func set_can_attack(value: bool) -> void: if value != _can_attack: _can_attack = value # 添加自定义逻辑(例如:冷却时间、状态更新等) print("攻击状态更新: ", value) _update_attack_cooldown() # 自定义方法示例 # 使用示例 func attack(): if can_attack(): print("执行攻击") # 攻击后进入冷却 set_can_attack(false) $CooldownTimer.start() # 启动冷却计时器 # 冷却结束回调 func _on_cooldown_timer_timeout(): set_can_attack(true) ``` ### 关键要点说明 1. **封装原理**: - 使用 `_can_attack` 作为私有存储变量(GDScript 无真正私有变量,但以下划线开头是命名约定) - `can_attack()` 作为 getter 方法返回当前值 - `set_can_attack()` 作为 setter 方法修改值并触发附加逻辑 2. **Setter 中的自定义逻辑**: ```gdscript func set_can_attack(value: bool) -> void: if value != _can_attack: # 仅在值变化时触发 _can_attack = value # 可添加验证逻辑 if value && !can_use_skill(): push_warning("无法在技能冷却时启用攻击") return # 触发状态更新 _update_attack_animation() emit_signal("attack_state_changed", value) # 发送信号 ``` 3. **Getter 扩展应用**: ```gdscript func can_attack() -> bool: # 添加额外条件判断 return _can_attack && is_on_floor() && !is_stunned() ``` ### 使用场景示例 ```gdscript # 玩家脚本中使用 func _physics_process(delta): if Input.is_action_just_pressed("attack") && can_attack(): perform_attack() set_can_attack(false) # 进入冷却 $CooldownTimer.start(1.0) # 1秒冷却 # 冷却结束恢复攻击能力 func _on_cooldown_timer_timeout(): set_can_attack(true) ``` ### 最佳实践建议 1. **封装优势**: - 集中控制状态变更逻辑 - 添加条件验证(如:`!is_stunned()`) - 自动触发关联操作(动画/音效/信号) 2. **命名规范**: - Getter 使用 `can_attack()`(类似属性名) - Setter 使用 `set_can_attack(value)` - 私有变量使用 `_can_attack` 3. **性能考虑**: - 在 setter 中添加 `if value != _can_attack` 避免不必要更新 - 复杂逻辑通过信号解耦[^1] > **应用场景**:适用于技能冷却、攻击间隔、状态切换等需要封装控制的布尔状态[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值