php封装核心在于边界意识而非修饰符规则:需明确锁住数据、放行方法;public属性等同裸露数据库字段;protected用于子类可定制场景;__construct只做必要赋值,依赖通过参数注入;封装到位的标准是能独立new且不报错。

PHP封装不是靠背修饰符规则学会的,而是从第一次写 class 就开始建立边界意识——你得清楚哪些数据该“锁起来”,哪些方法该“开门放行”,否则后期加校验、换存储、做单元测试时,全是补丁。
为什么直接 public $name 会埋雷
新手常写这样的代码:class User { public $name; },然后在别处直接 $user->name = "张三"。表面能跑,但一旦需求变成“用户名必须大于2个字符且不能含特殊符号”,你就得全局搜索 ->name =,逐个补逻辑。这不是改代码,是修漏洞。
- 所有 public 属性都等同于把数据库字段裸露给外部,失去控制权
- 后续加日志、缓存、权限判断时,无法统一拦截,只能到处复制粘贴
- 单元测试时无法模拟异常输入,因为赋值不经过任何验证入口
正确做法是立刻补上 setName() 和 getName(),哪怕初始逻辑只是简单赋值和返回——先立住门框,再装锁。
protected 不是“半私有”,而是继承链的契约
很多教程一上来就强调“全用 private”,结果子类想扩展功能只能复制父类全部逻辑。真实项目里,protected 才是高频主力。
-
private function connectDb()写死在父类里 → 子类换 MySQL 为 PostgreSQL 时无解 - 改成
protected function createConnection()→ 子类重写即可,父类save()完全不用动 -
protected $cacheTTL允许子类根据场景调整过期时间,而private会逼你暴露 setter 或硬编码
判断标准很简单:这个东西未来是否可能被子类定制?如果是,就用 protected;如果纯属当前类内部临时状态(比如 $this->cachedResult),才用 private。
__construct() 里只放“让对象活下来”的事
构造函数不是启动器,也不是初始化钩子。它唯一任务是让新对象处于可用状态,而不是让它立刻干活。
- 错:在
__construct()里调用file_get_contents('config.json')—— 对象无法被 DI 容器管理,也无法 mock 配置做测试 - 错:在
__construct()里执行$this->db->query("SELECT ...")—— new 一个对象就查库,违背单一职责,也导致无法实例化后配置再运行 - 对:只做
$this->id = $id、$this->status = self::STATUS_DRAFT这类纯赋值动作
真正需要加载或连接的依赖,一律走构造参数注入,比如 public function __construct(LoggerInterface $logger)。这样对象可测、可替、可复用。
封装成败看能不能独立 new 出来
写完一个类,立刻在空白脚本里试:删掉所有 require、去掉框架上下文,只写 $obj = new User();,它是否不报错?能否调用 $obj->getName() 返回空或默认值?如果不行,说明它还依赖外部状态,封装没到位。
常见卡点是属性没设默认值(如 private $email; 没初始化)、构造函数强依赖未传参、或方法里硬编码了全局函数(如直接调用 date() 而不抽成可替换的 protected function now())。这些细节不处理,封装就只是语法层面的自我安慰。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











