属性与方法
属性和方法是类的核心组成部分。属性(也称为成员变量)用于存储对象的状态数据,而方法(也称为成员函数)用于定义对象的行为。理解属性和方法的正确使用是掌握面向对象编程的关键。
学习目标
完成本节学习后,你将能够:
- 理解属性的定义和使用
- 掌握不同访问修饰符的作用
- 学会创建和使用各种类型的方法
- 理解$this关键字的使用
- 掌握静态属性和静态方法
- 学会使用类型声明和返回类型
- 了解魔术方法的原理和应用
属性(Properties)
属性的基本概念
属性是类中用于存储数据的变量。每个对象实例都有自己的一组属性,这些属性构成了对象的状态。
<?php
class Product {
// 公共属性 - 可以从任何地方访问
public $name;
public $price;
// 受保护的属性 - 只能在类内部和子类中访问
protected $category;
protected $stock;
// 私有属性 - 只能在类内部访问
private $id;
private $createdAt;
public function __construct($name, $price, $category) {
$this->id = uniqid('product_'); // 使用$this访问属性
$this->name = $name;
$this->price = $price;
$this->category = $category;
$this->stock = 0;
$this->createdAt = date('Y-m-d H:i:s');
}
// 获取器方法(Getter)
public function getId() {
return $this->id;
}
public function getCategory() {
return $this->category;
}
public function getStock() {
return $this->stock;
}
public function getCreatedAt() {
return $this->createdAt;
}
// 设置器方法(Setter)
public function setCategory($category) {
$this->category = $category;
}
public function setStock($stock) {
if ($stock >= 0) {
$this->stock = $stock;
return true;
}
return false;
}
// 业务方法
public function isInStock() {
return $this->stock > 0;
}
public function getInfo() {
$stockStatus = $this->isInStock() ? "有库存" : "缺货";
return "产品:{$this->name},价格:¥{$this->price},库存状态:{$stockStatus}";
}
}
// 使用示例
$product = new Product("笔记本电脑", 5999.99, "电子产品");
// 访问公共属性
echo "产品名称:" . $product->name . "\n";
echo "产品价格:" . $product->price . "\n";
// 通过getter访问私有/受保护属性
echo "产品ID:" . $product->getId() . "\n";
echo "产品类别:" . $product->getCategory() . "\n";
// 通过setter修改属性
$product->setStock(50);
echo "产品库存:" . $product->getStock() . "\n";
// 调用业务方法
echo $product->getInfo() . "\n";
// 错误示例 - 不能直接访问私有属性
// echo $product->id; // 错误:私有属性
// echo $product->createdAt; // 错误:私有属性
// echo $product->category; // 错误:受保护属性
?>
属性的类型声明
<?php
class Employee {
// PHP 7.4+ 支持属性类型声明
private int $id;
private string $name;
private float $salary;
private bool $isActive;
private array $skills;
private ?DateTime $hireDate; // 可空类型
private string $department = 'IT'; // 默认值
public function __construct(int $id, string $name, float $salary) {
$this->id = $id;
$this->name = $name;
$this->salary = $salary;
$this->isActive = true;
$this->skills = [];
$this->hireDate = null;
}
public function addSkill(string $skill): void {
if (!in_array($skill, $this->skills)) {
$this->skills[] = $skill;
}
}
public function setHireDate(DateTime $date): void {
$this->hireDate = $date;
}
public function getProfile(): array {
return [
'id' => $this->id,
'name' => $this->name,
'salary' => $this->salary,
'isActive' => $this->isActive,
'skills' => $this->skills,
'hireDate' => $this->hireDate ? $this->hireDate->format('Y-m-d') : null,
'department' => $this->department
];
}
}
// 使用示例
$employee = new Employee(1, "张三", 8000.00);
$employee->addSkill("PHP");
$employee->addSkill("JavaScript");
$employee->addSkill("MySQL");
$employee->setHireDate(new DateTime('2020-01-15'));
$profile = $employee->getProfile();
print_r($profile);
?>
只读属性(PHP 8.1+)
<?php
// PHP 8.1+ 支持只读属性
class User {
public readonly int $id;
public readonly string $email;
public readonly DateTime $createdAt;
public function __construct(int $id, string $email) {
$this->id = $id;
$this->email = $email;
$this->createdAt = new DateTime();
}
// 只读属性只能在构造函数或声明时赋值
// 下面的方法会导致错误:
// public function setEmail(string $email): void {
// $this->email = $email; // 错误:只读属性不能修改
// }
}
$user = new User(1, "user@example.com");
echo "用户ID:" . $user->id . "\n";
echo "用户邮箱:" . $user->email . "\n";
echo "创建时间:" . $user->createdAt->format('Y-m-d H:i:s') . "\n";
// $user->email = "new@example.com"; // 错误:不能修改只读属性
?>
方法(Methods)
方法的定义和使用
方法是类中定义的函数,用于执行特定的操作或实现特定的功能。
<?php
class Calculator {
private float $result = 0.0;
private array $history = [];
// 基本方法
public function add(float $number): float {
$this->result += $number;
$this->addToHistory("add", $number);
return $this->result;
}
public function subtract(float $number): float {
$this->result -= $number;
$this->addToHistory("subtract", $number);
return $this->result;
}
public function multiply(float $number): float {
$this->result *= $number;
$this->addToHistory("multiply", $number);
return $this->result;
}
public function divide(float $number): float {
if ($number == 0) {
throw new InvalidArgumentException("除数不能为零");
}
$this->result /= $number;
$this->addToHistory("divide", $number);
return $this->result;
}
// 可变参数方法
public function addMultiple(float ...$numbers): float {
foreach ($numbers as $number) {
$this->result += $number;
}
$this->addToHistory("addMultiple", $numbers);
return $this->result;
}
// 带默认参数的方法
public function power(float $exponent = 2): float {
$this->result = pow($this->result, $exponent);
$this->addToHistory("power", $exponent);
return $this->result;
}
// 返回数组的方法
public function getHistory(): array {
return $this->history;
}
// 返回对象的方法
public function clone(): Calculator {
$newCalc = new Calculator();
$newCalc->result = $this->result;
$newCalc->history = $this->history;
return $newCalc;
}
// 链式调用方法
public function reset(): Calculator {
$this->result = 0;
$this->history = [];
return $this; // 返回$this支持链式调用
}
public function getResult(): float {
return $this->result;
}
// 私有辅助方法
private function addToHistory(string $operation, $value): void {
$this->history[] = [
'operation' => $operation,
'value' => $value,
'result' => $this->result,
'timestamp' => date('Y-m-d H:i:s')
];
}
// 静态方法
public static function factorial(int $n): int {
if ($n < 0) {
throw new InvalidArgumentException("阶乘不能为负数");
}
if ($n === 0 || $n === 1) {
return 1;
}
return $n * self::factorial($n - 1);
}
public static function isEven(int $number): bool {
return $number % 2 === 0;
}
}
// 使用示例
echo "=== 计算器示例 ===\n";
$calc = new Calculator();
// 链式调用
$result = $calc->add(10)->multiply(2)->subtract(5)->divide(3)->getResult();
echo "计算结果:(10 + 5) * 2 / 3 = $result\n";
// 可变参数
$calc->reset()->addMultiple(1, 2, 3, 4, 5);
echo "多参数加法结果:" . $calc->getResult() . "\n";
// 默认参数
$calc->reset()->add(4)->power(); // 使用默认参数2
echo "4的平方:" . $calc->getResult() . "\n";
$calc->reset()->add(2)->power(3); // 指定参数
echo "2的3次方:" . $calc->getResult() . "\n";
// 静态方法
echo "5的阶乘:" . Calculator::factorial(5) . "\n";
echo "6是否为偶数:" . (Calculator::isEven(6) ? "是" : "否") . "\n";
// 查看历史记录
$history = $calc->getHistory();
echo "计算历史:\n";
foreach ($history as $entry) {
echo " {$entry['timestamp']} - {$entry['operation']}({$entry['value']}) = {$entry['result']}\n";
}
// 克隆计算器
$clonedCalc = $calc->clone();
echo "克隆计算器的结果:" . $clonedCalc->getResult() . "\n";
?>
$this关键字
$this是一个特殊的变量,它指向当前对象的实例,用于在类的内部访问对象的属性和方法。
<?php
class Person {
private string $name;
private int $age;
private array $hobbies = [];
public function __construct(string $name, int $age) {
$this->name = $name; // $this指向当前对象
$this->age = $age;
}
public function getName(): string {
return $this->name; // 访问当前对象的属性
}
public function getAge(): int {
return $this->age;
}
public function addHobby(string $hobby): void {
$this->hobbies[] = $hobby; // 修改当前对象的属性
}
public function getHobbies(): array {
return $this->hobbies;
}
public function introduce(): string {
$hobbyStr = empty($this->hobbies) ? "没有特殊爱好" : implode("、", $this->hobbies);
return "大家好,我叫{$this->name},今年{$this->age}岁。我的爱好是{$hobbyStr}。";
}
public function celebrateBirthday(): void {
$this->age++; // 增加年龄
echo "祝{$this->name}生日快乐!现在{$this->age}岁了!\n";
}
// $this也可以用于调用其他方法
public function getDetailedInfo(): array {
return [
'name' => $this->getName(),
'age' => $this->getAge(),
'hobbies' => $this->getHobbies(),
'introduction' => $this->introduce()
];
}
// $this在方法间传递
public function compareAge(Person $other): string {
if ($this->age > $other->age) {
return "{$this->name}比{$other->name}大" . ($this->age - $other->age) . "岁";
} elseif ($this->age < $other->age) {
return "{$this->name}比{$other->name}小" . ($other->age - $this->age) . "岁";
} else {
return "{$this->name}和{$other->name}同岁";
}
}
// $this用于回调函数
public function processWithCallback(callable $callback) {
$result = $callback($this); // 将当前对象传递给回调函数
return $result;
}
}
// 使用示例
$person1 = new Person("张三", 25);
$person2 = new Person("李四", 28);
$person1->addHobby("阅读");
$person1->addHobby("游泳");
echo $person1->introduce() . "\n";
$person1->celebrateBirthday();
echo $person1->compareAge($person2) . "\n";
// 使用回调函数
$result = $person1->processWithCallback(function($person) {
return $person->getName() . "的处理结果";
});
echo "回调处理结果:$result\n";
$info = $person1->getDetailedInfo();
print_r($info);
?>
访问修饰符详解
public(公共)
<?php
class PublicExample {
public $publicProperty = "公共属性";
public $counter = 0;
public function publicMethod() {
$this->counter++;
return "这是一个公共方法,调用次数:{$this->counter}";
}
public function accessFromOutside() {
echo "在类内部访问公共属性:{$this->publicProperty}\n";
echo "在类内部调用公共方法:" . $this->publicMethod() . "\n";
}
}
$publicExample = new PublicExample();
// 从外部访问
echo $publicExample->publicProperty . "\n"; // 直接访问公共属性
echo $publicExample->publicMethod() . "\n"; // 直接调用公共方法
$publicExample->publicProperty = "修改后的公共属性";
echo $publicExample->publicProperty . "\n";
$publicExample->accessFromOutside();
?>
protected(受保护)
<?php
class ParentClass {
protected $protectedProperty = "受保护属性";
protected $counter = 0;
protected function protectedMethod() {
$this->counter++;
return "这是一个受保护方法,调用次数:{$this->counter}";
}
public function accessFromInside() {
echo "在父类内部访问受保护属性:{$this->protectedProperty}\n";
echo "在父类内部调用受保护方法:" . $this->protectedMethod() . "\n";
}
}
class ChildClass extends ParentClass {
public function accessFromChild() {
// 子类可以访问父类的受保护成员
echo "在子类中访问父类受保护属性:{$this->protectedProperty}\n";
echo "在子类中调用父类受保护方法:" . $this->protectedMethod() . "\n";
// 修改受保护属性
$this->protectedProperty = "被子类修改的受保护属性";
echo "修改后的受保护属性:{$this->protectedProperty}\n";
}
}
$parent = new ParentClass();
$child = new ChildClass();
// 从外部无法直接访问受保护成员
// echo $parent->protectedProperty; // 错误
// echo $parent->protectedMethod(); // 错误
// 通过公共方法间接访问
$parent->accessFromInside();
// 子类可以访问受保护成员
$child->accessFromChild();
?>
private(私有)
<?php
class PrivateExample {
private $privateProperty = "私有属性";
private $counter = 0;
private function privateMethod() {
$this->counter++;
return "这是一个私有方法,调用次数:{$this->counter}";
}
public function accessFromInside() {
// 类内部可以访问私有成员
echo "在类内部访问私有属性:{$this->privateProperty}\n";
echo "在类内部调用私有方法:" . $this->privateMethod() . "\n";
}
public function modifyPrivateProperty() {
$this->privateProperty = "修改后的私有属性";
}
public function getPrivateProperty() {
return $this->privateProperty;
}
public function callPrivateMethod() {
return $this->privateMethod();
}
}
class ChildOfPrivate extends PrivateExample {
public function tryAccessPrivate() {
// 子类无法访问父类的私有成员
// echo $this->privateProperty; // 错误
// echo $this->privateMethod(); // 错误
echo "子类无法直接访问父类的私有成员\n";
}
}
$privateExample = new PrivateExample();
$child = new ChildOfPrivate();
// 从外部无法直接访问私有成员
// echo $privateExample->privateProperty; // 错误
// echo $privateExample->privateMethod(); // 错误
// 通过公共方法间接访问
$privateExample->accessFromInside();
$privateExample->modifyPrivateProperty();
echo "通过getter访问私有属性:" . $privateExample->getPrivateProperty() . "\n";
echo "通过公共方法调用私有方法:" . $privateExample->callPrivateMethod() . "\n";
$child->tryAccessPrivate();
?>
静态属性和静态方法
静态属性
<?php
class Car {
// 静态属性 - 属于类,不属于任何实例
private static $totalCars = 0;
private static $manufacturer = "示例汽车厂";
// 实例属性 - 属于每个对象实例
private $model;
private $color;
private $price;
public function __construct($model, $color, $price) {
$this->model = $model;
$this->color = $color;
$this->price = $price;
// 访问和修改静态属性
self::$totalCars++;
echo "创建了一辆{$this->color}的{$this->model},总产量:" . self::$totalCars . "\n";
}
public function __destruct() {
self::$totalCars--;
echo "销毁了一辆{$this->model},当前总产量:" . self::$totalCars . "\n";
}
// 静态方法访问静态属性
public static function getTotalCars() {
return self::$totalCars;
}
public static function getManufacturer() {
return self::$manufacturer;
}
public static function setManufacturer($manufacturer) {
self::$manufacturer = $manufacturer;
}
public static function getProductionStats() {
return [
'manufacturer' => self::$manufacturer,
'total_produced' => self::$totalCars
];
}
// 实例方法访问静态属性
public function getModel() {
return $this->model . " (" . self::$manufacturer . ")";
}
}
// 使用示例
echo "=== 静态属性示例 ===\n";
// 访问静态属性
echo "初始产量:" . Car::getTotalCars() . "\n";
echo "制造商:" . Car::getManufacturer() . "\n";
// 修改静态属性
Car::setManufacturer("高级汽车厂");
echo "修改后制造商:" . Car::getManufacturer() . "\n";
// 创建对象(会影响静态属性)
$car1 = new Car("Model S", "红色", 500000);
$car2 = new Car("Model X", "蓝色", 600000);
$car3 = new Car("Model 3", "白色", 350000);
echo "当前产量:" . Car::getTotalCars() . "\n";
// 实例方法访问静态属性
echo "汽车1型号:" . $car1->getModel() . "\n";
// 销毁对象(也会影响静态属性)
unset($car1);
echo "销毁一辆车后产量:" . Car::getTotalCars() . "\n";
?>
静态方法
<?php
class MathHelper {
// 静态常量
const PI = 3.14159265359;
const E = 2.71828182846;
// 静态方法 - 不需要创建实例就可以调用
public static function circleArea(float $radius): float {
return self::PI * $radius * $radius;
}
public static function circleCircumference(float $radius): float {
return 2 * self::PI * $radius;
}
public static function rectangleArea(float $width, float $height): float {
return $width * $height;
}
public static function rectanglePerimeter(float $width, float $height): float {
return 2 * ($width + $height);
}
// 静态方法调用其他静态方法
public static function circleInfo(float $radius): array {
return [
'radius' => $radius,
'area' => self::circleArea($radius),
'circumference' => self::circleCircumference($radius)
];
}
// 静态工厂方法 - 创建对象实例
public static function createCircle(float $radius): Circle {
return new Circle($radius);
}
public static function createRectangle(float $width, float $height): Rectangle {
return new Rectangle($width, $height);
}
// 工具方法
public static function formatNumber(float $number, int $decimals = 2): string {
return number_format($number, $decimals);
}
// 数值验证
public static function isPositive(float $number): bool {
return $number > 0;
}
public static function isEven(int $number): bool {
return $number % 2 === 0;
}
public static function isPrime(int $number): bool {
if ($number <= 1) return false;
if ($number <= 3) return true;
if ($number % 2 === 0 || $number % 3 === 0) return false;
for ($i = 5; $i * $i <= $number; $i += 6) {
if ($number % $i === 0 || $number % ($i + 2) === 0) {
return false;
}
}
return true;
}
}
// 配套的形状类
class Circle {
private float $radius;
public function __construct(float $radius) {
$this->radius = $radius;
}
public function getRadius(): float {
return $this->radius;
}
public function getArea(): float {
return MathHelper::circleArea($this->radius);
}
public function getCircumference(): float {
return MathHelper::circleCircumference($this->radius);
}
}
class Rectangle {
private float $width;
private float $height;
public function __construct(float $width, float $height) {
$this->width = $width;
$this->height = $height;
}
public function getWidth(): float {
return $this->width;
}
public function getHeight(): float {
return $this->height;
}
public function getArea(): float {
return MathHelper::rectangleArea($this->width, $this->height);
}
public function getPerimeter(): float {
return MathHelper::rectanglePerimeter($this->width, $this->height);
}
}
// 使用示例
echo "=== 静态方法示例 ===\n";
// 直接调用静态方法,无需创建对象
$radius = 5;
$area = MathHelper::circleArea($radius);
$circumference = MathHelper::circleCircumference($radius);
echo "半径为{$radius}的圆:\n";
echo "面积:" . MathHelper::formatNumber($area) . "\n";
echo "周长:" . MathHelper::formatNumber($circumference) . "\n";
// 调用返回数组的静态方法
$circleInfo = MathHelper::circleInfo(3);
echo "\n半径为3的圆的详细信息:\n";
print_r($circleInfo);
// 使用静态工厂方法创建对象
$circle = MathHelper::createCircle(4);
$rectangle = MathHelper::createRectangle(6, 4);
echo "\n使用工厂方法创建的形状:\n";
echo "圆的半径:" . $circle->getRadius() . ",面积:" . MathHelper::formatNumber($circle->getArea()) . "\n";
echo "矩形的尺寸:" . $rectangle->getWidth() . "x" . $rectangle->getHeight() . ",面积:" . $rectangle->getArea() . "\n";
// 数值验证
echo "\n数值验证:\n";
echo "7是质数吗?" . (MathHelper::isPrime(7) ? "是" : "否") . "\n";
echo "12是偶数吗?" . (MathHelper::isEven(12) ? "是" : "否") . "\n";
echo "-5是正数吗?" . (MathHelper::isPositive(-5) ? "是" : "否") . "\n";
?>
魔术方法
PHP提供了一些以双下划线开头的特殊方法,称为魔术方法。这些方法在特定情况下会被自动调用。
__toString() 方法
<?php
class Book {
private $title;
private $author;
private $price;
private $year;
public function __construct($title, $author, $price, $year) {
$this->title = $title;
$this->author = $author;
$this->price = $price;
$this->year = $year;
}
// 魔术方法:当对象被当作字符串使用时调用
public function __toString() {
return "《{$this->title}》- {$this->author} ({$this->year}年出版) ¥{$this->price}";
}
// 其他魔术方法
public function __invoke($discount = 0) {
$finalPrice = $this->price * (1 - $discount);
return "打折后价格:¥" . number_format($finalPrice, 2);
}
public function __debugInfo() {
return [
'title' => $this->title,
'author' => $this->author,
'price' => $this->price,
'year' => $this->year,
'price_formatted' => '¥' . number_format($this->price, 2)
];
}
}
// 使用示例
$book = new Book("PHP从入门到精通", "张三", 89.99, 2023);
// 对象被当作字符串使用时自动调用__toString()
echo $book . "\n";
// 对象被当作函数调用时自动调用__invoke()
echo $book(0.1) . "\n"; // 9折
// var_dump会显示__debugInfo()返回的信息
var_dump($book);
?>
__set() 和 __get() 方法
<?php
class DynamicProperties {
private $data = [];
private $allowedProperties = ['name', 'age', 'email'];
// 当设置未定义或不可访问的属性时调用
public function __set($name, $value) {
echo "尝试设置属性:$name = $value\n";
if (in_array($name, $this->allowedProperties)) {
$this->data[$name] = $value;
} else {
echo "属性 '$name' 不允许设置\n";
}
}
// 当访问未定义或不可访问的属性时调用
public function __get($name) {
echo "尝试获取属性:$name\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
echo "属性 '$name' 不存在\n";
return null;
}
// 检查属性是否存在
public function __isset($name) {
return isset($this->data[$name]);
}
// 删除属性
public function __unset($name) {
echo "尝试删除属性:$name\n";
unset($this->data[$name]);
}
// 检查属性是否允许
public function isPropertyAllowed($name): bool {
return in_array($name, $this->allowedProperties);
}
}
// 使用示例
echo "=== __set() 和 __get() 示例 ===\n";
$obj = new DynamicProperties();
// 通过魔术方法设置属性
$obj->name = "张三"; // 允许的属性
$obj->age = 25; // 允许的属性
$obj->email = "zhang@example.com"; // 允许的属性
$obj->phone = "1234567890"; // 不允许的属性
// 通过魔术方法获取属性
echo "姓名:" . $obj->name . "\n";
echo "年龄:" . $obj->age . "\n";
echo "邮箱:" . $obj->email . "\n";
echo "电话:" . $obj->phone . "\n";
// 检查属性是否存在
echo "姓名属性是否存在:" . (isset($obj->name) ? "是" : "否") . "\n";
// 删除属性
unset($obj->age);
echo "删除后姓名:" . $obj->name . "\n";
echo "删除后年龄:" . $obj->age . "\n";
?>
__call() 和 __callStatic() 方法
<?php
class MethodInterception {
// 当调用未定义或不可访问的实例方法时调用
public function __call($method, $arguments) {
echo "尝试调用实例方法:$method\n";
echo "参数:" . implode(', ', $arguments) . "\n";
// 动态处理方法调用
if (strpos($method, 'get') === 0) {
$property = strtolower(substr($method, 3));
return "获取属性 $property 的值";
}
if (strpos($method, 'set') === 0) {
$property = strtolower(substr($method, 3));
return "设置属性 $property 的值为:" . ($arguments[0] ?? 'null');
}
throw new BadMethodCallException("方法 $method 不存在");
}
// 当调用未定义或不可访问的静态方法时调用
public static function __callStatic($method, $arguments) {
echo "尝试调用静态方法:$method\n";
echo "参数:" . implode(', ', $arguments) . "\n";
// 静态方法的动态处理
switch ($method) {
case 'calculate':
$operation = $arguments[0] ?? null;
$a = $arguments[1] ?? 0;
$b = $arguments[2] ?? 0;
switch ($operation) {
case 'add':
return $a + $b;
case 'multiply':
return $a * $b;
default:
return "未知操作";
}
case 'format':
$value = $arguments[0] ?? null;
return "格式化:" . json_encode($value);
default:
throw new BadMethodCallException("静态方法 $method 不存在");
}
}
// 已定义的方法,不会触发__call
public function existingMethod() {
return "这是一个已定义的方法";
}
}
// 使用示例
echo "=== __call() 和 __callStatic() 示例 ===\n";
$obj = new MethodInterception();
// 调用已定义的方法(不会触发__call)
echo "已定义方法:" . $obj->existingMethod() . "\n";
// 调用未定义的方法(会触发__call)
echo $obj->getName("John") . "\n";
echo $obj->setAge(25) . "\n";
// 调用未定义的静态方法(会触发__callStatic)
$result = MethodInterception::calculate('add', 10, 5);
echo "计算结果:$result\n";
$formatted = MethodInterception::format(['name' => 'John', 'age' => 25]);
echo "格式化结果:$formatted\n";
// 尝试调用不存在的方法(会抛出异常)
try {
$obj->nonExistentMethod();
} catch (BadMethodCallException $e) {
echo "捕获异常:" . $e->getMessage() . "\n";
}
?>
实际应用示例
简单的用户管理类
<?php
class UserManager {
private static $users = [];
private static $nextId = 1;
// 静态方法:创建用户
public static function createUser($username, $email, $password) {
if (self::userExists($username)) {
throw new InvalidArgumentException("用户名已存在");
}
if (self::emailExists($email)) {
throw new InvalidArgumentException("邮箱已存在");
}
$user = [
'id' => self::$nextId++,
'username' => $username,
'email' => $email,
'password_hash' => password_hash($password, PASSWORD_DEFAULT),
'created_at' => date('Y-m-d H:i:s'),
'is_active' => true,
'last_login' => null
];
self::$users[$user['id']] = $user;
return new User($user);
}
// 静态方法:验证用户
public static function authenticate($username, $password) {
$user = self::getUserByUsername($username);
if (!$user) {
throw new Exception("用户名或密码错误");
}
if (!$user['is_active']) {
throw new Exception("用户账户已被禁用");
}
if (!password_verify($password, $user['password_hash'])) {
throw new Exception("用户名或密码错误");
}
// 更新登录时间
self::$users[$user['id']]['last_login'] = date('Y-m-d H:i:s');
return new User($user);
}
// 静态方法:获取用户
public static function getUserById($id) {
return self::$users[$id] ?? null;
}
public static function getUserByUsername($username) {
foreach (self::$users as $user) {
if ($user['username'] === $username) {
return $user;
}
}
return null;
}
public static function getUserByEmail($email) {
foreach (self::$users as $user) {
if ($user['email'] === $email) {
return $user;
}
}
return null;
}
// 静态方法:检查用户是否存在
public static function userExists($username) {
return self::getUserByUsername($username) !== null;
}
public static function emailExists($email) {
return self::getUserByEmail($email) !== null;
}
// 静态方法:获取所有用户
public static function getAllUsers() {
$userObjects = [];
foreach (self::$users as $user) {
$userObjects[] = new User($user);
}
return $userObjects;
}
// 静态方法:获取活跃用户数
public static function getActiveUserCount() {
$count = 0;
foreach (self::$users as $user) {
if ($user['is_active']) {
$count++;
}
}
return $count;
}
// 静态方法:清除所有用户
public static function clearAllUsers() {
self::$users = [];
self::$nextId = 1;
}
}
// 用户对象类
class User {
private $data;
public function __construct($userData) {
$this->data = $userData;
}
public function getId() {
return $this->data['id'];
}
public function getUsername() {
return $this->data['username'];
}
public function getEmail() {
return $this->data['email'];
}
public function getCreatedAt() {
return $this->data['created_at'];
}
public function getLastLogin() {
return $this->data['last_login'];
}
public function isActive() {
return $this->data['is_active'];
}
public function toArray() {
return [
'id' => $this->getId(),
'username' => $this->getUsername(),
'email' => $this->getEmail(),
'created_at' => $this->getCreatedAt(),
'last_login' => $this->getLastLogin(),
'is_active' => $this->isActive()
];
}
public function __toString() {
return "用户[{$this->getId()}]: {$this->getUsername()} ({$this->getEmail()})";
}
}
// 使用示例
echo "=== 用户管理系统示例 ===\n";
try {
// 清理现有数据
UserManager::clearAllUsers();
// 创建用户
$user1 = UserManager::createUser("alice", "alice@example.com", "password123");
$user2 = UserManager::createUser("bob", "bob@example.com", "password456");
echo "用户创建成功\n";
echo "活跃用户数:" . UserManager::getActiveUserCount() . "\n";
// 用户登录
$loggedInUser = UserManager::authenticate("alice", "password123");
echo "用户登录成功:" . $loggedInUser . "\n";
// 获取所有用户
$allUsers = UserManager::getAllUsers();
echo "所有用户:\n";
foreach ($allUsers as $user) {
echo "- " . $user . "\n";
}
// 获取用户详细信息
$userInfo = $loggedInUser->toArray();
echo "用户详细信息:\n";
print_r($userInfo);
} catch (Exception $e) {
echo "错误:" . $e->getMessage() . "\n";
}
?>
总结
属性和方法是面向对象编程的基础构件,正确理解和使用它们对于构建高质量的面向对象应用程序至关重要。
关键要点:
-
属性管理:
- 属性用于存储对象状态
- 使用访问修饰符控制属性的可访问性
- 支持类型声明和默认值
- 提供getter和setter方法进行受控访问
-
方法设计:
- 方法定义对象的行为
- 支持参数类型声明和返回类型
- 可变参数和默认参数增加灵活性
- 链式调用提高代码可读性
-
访问控制:
public:完全开放,可从任何地方访问protected:类内部和子类可访问private:仅类内部可访问
-
静态成员:
- 静态属性和方法属于类而不是实例
- 通过类名直接访问,无需创建对象
- 适合实现工具方法和共享数据
-
魔术方法:
- 在特定情况下自动调用的特殊方法
- 提供对象的高级功能
- 谨慎使用,避免过度复杂化
最佳实践:
- 保持属性私有,通过方法进行访问控制
- 为方法选择清晰的命名和单一职责
- 合理使用静态方法和实例方法
- 优先使用类型声明提高代码安全性
- 避免滥用魔术方法,保持代码简洁明了
通过本节学习,你应该能够熟练地定义和使用类的属性与方法,为后续学习更高级的面向对象特性打下坚实基础。