技术分享

PHP判断函数大全:从isset到str_contains,一文掌握所有核心技巧!

作者头像 人称外号大脸猫
16 阅读
PHP判断函数大全:从isset到str_contains,一文掌握所有核心技巧!

基础不牢,地动山摇!PHP判断函数是每个开发者必须精通的基本功

在日常开发中,我们几乎每行代码都在做判断。变量是否存在?数据是否合法?条件是否满足?这些看似简单的判断,却是构建稳定应用的基石。

据不完全统计,PHP项目中近30%的bug都与判断逻辑不当有关。今天,我们就系统梳理PHP的所有判断函数,帮你打好扎实的基础!

一、变量存在性判断:isset vs empty vs is_null

1.1 三者的根本区别

// 测试数据
$var1 = null;
$var2 = '';
$var3 = 0;
$var4 = false;
$var5 = '0';
$var6 = [];
$var7 = 'Hello';

// 对比结果
echo "变量 | isset | empty | is_null\n";
echo "null | " . (isset($var1) ? 'true' : 'false') . " | " . (empty($var1) ? 'true' : 'false') . " | " . (is_null($var1) ? 'true' : 'false') . "\n";
echo "空字符串 | " . (isset($var2) ? 'true' : 'false') . " | " . (empty($var2) ? 'true' : 'false') . " | " . (is_null($var2) ? 'true' : 'false') . "\n";
echo "数字0 | " . (isset($var3) ? 'true' : 'false') . " | " . (empty($var3) ? 'true' : 'false') . " | " . (is_null($var3) ? 'true' : 'false') . "\n";

执行结果:

变量      | isset | empty | is_null
null     | false | true  | true
空字符串 | true  | true  | false
数字0    | true  | true  | false
false    | true  | true  | false
'0'      | true  | true  | false
空数组   | true  | true  | false
'Hello'  | true  | false | false

1.2 实际应用场景

// 表单数据处理
if (isset($_POST['username'])) {
    // 用户提交了用户名
    $username = trim($_POST['username']);
    
    if (!empty($username)) {
        // 用户名非空,进行进一步处理
        processUsername($username);
    } else {
        // 用户名为空
        throw new Exception('用户名不能为空');
    }
} else {
    // 用户名字段不存在
    throw new Exception('缺少必要参数');
}

// 配置项读取
$config = [
    'debug' => true,
    'cache_time' => 3600
];

// 安全读取配置,提供默认值
$debugMode = isset($config['debug']) ? $config['debug'] : false;
$cacheTime = $config['cache_time'] ?? 3600; // PHP 7+ 空合并运算符

二、数据类型判断:让代码类型安全

2.1 基本类型判断函数

// 数值类型判断
$var = 42;
is_int($var);        // true
is_integer($var);    // true - is_int的别名
is_long($var);       // true - 同样是别名

$var = 3.14;
is_float($var);      // true
is_double($var);     // true - is_float的别名

// 字符串判断
$var = "Hello";
is_string($var);     // true

// 布尔值判断
$var = true;
is_bool($var);       // true

2.2 复合类型判断

// 数组判断
$var = [1, 2, 3];
is_array($var);      // true

// 对象判断
$var = new stdClass();
is_object($var);     // true

// 可调用判断
$var = function() { return 'hello'; };
is_callable($var);   // true

// 迭代器判断(PHP 7.1+)
$var = new ArrayIterator([1,2,3]);
is_iterable($var);   // true

2.3 特殊类型判断

// 资源判断
$file = fopen('test.txt', 'r');
is_resource($file);  // true
fclose($file);

// NULL判断
$var = null;
is_null($var);       // true

// 标量判断(单值类型)
is_scalar(123);      // true - 整数是标量
is_scalar('hello');  // true - 字符串是标量
is_scalar([1,2]);    // false - 数组不是标量
is_scalar(new stdClass()); // false - 对象不是标量

三、比较运算符:== 与 === 的终极对决

3.1 松散比较(==)的隐式转换

// 经典陷阱案例
echo "松散比较结果:\n";
echo "'123' == 123: " . ('123' == 123 ? 'true' : 'false') . "\n"; // true
echo "'123abc' == 123: " . ('123abc' == 123 ? 'true' : 'false') . "\n"; // true - 注意!
echo "'0' == false: " . ('0' == false ? 'true' : 'false') . "\n"; // true
echo "'' == false: " . ('' == false ? 'true' : 'false') . "\n"; // true
echo "0 == false: " . (0 == false ? 'true' : 'false') . "\n"; // true

3.2 严格比较(===)的类型安全

echo "\n严格比较结果:\n";
echo "'123' === 123: " . ('123' === 123 ? 'true' : 'false') . "\n"; // false
echo "'0' === false: " . ('0' === false ? 'true' : 'false') . "\n"; // false
echo "0 === false: " . (0 === false ? 'true' : 'false') . "\n"; // false

3.3 最佳实践建议

// 数据库ID比较
$userIdFromDb = '123'; // 数据库返回的字符串
$userIdFromInput = 123; // 用户输入的整数

// 错误做法
if ($userIdFromDb == $userIdFromInput) {
    // 这里会执行,但可能不是你想要的结果
}

// 正确做法
if ((int)$userIdFromDb === $userIdFromInput) {
    // 明确类型转换后比较
}

// 或者
if ($userIdFromDb === (string)$userIdFromInput) {
    // 统一类型后比较
}

四、字符串判断:PHP 8新特性革命

4.1 传统字符串判断方法

$email = 'user@example.com';
$url = 'https://www.example.com';
$filename = 'document.pdf';

// 判断是否包含子串
if (strpos($email, '@') !== false) {
    echo "有效的邮箱地址\n";
}

// 判断是否以某字符串开头
if (strpos($url, 'https://') === 0) {
    echo "使用HTTPS协议\n";
}

// 判断是否以某字符串结尾
if (substr($filename, -4) === '.pdf') {
    echo "PDF文件\n";
}

4.2 PHP 8新函数的优雅写法

// 更直观的字符串判断
if (str_contains($email, '@')) {
    echo "有效的邮箱地址\n";
}

if (str_starts_with($url, 'https://')) {
    echo "使用HTTPS协议\n";
}

if (str_ends_with($filename, '.pdf')) {
    echo "PDF文件\n";
}

4.3 大小写不敏感判断

$text = "Hello World";

// 传统方法
if (stripos($text, 'hello') !== false) {
    echo "包含hello(不区分大小写)\n";
}

// 如果需要使用新函数,可以结合strtolower
if (str_contains(strtolower($text), 'hello')) {
    echo "包含hello\n";
}

五、数组判断:避免Undefined offset警告

5.1 数组键值存在性检查

$user = [
    'name' => '张三',
    'age' => 25,
    'email' => 'zhangsan@example.com'
];

// 检查键是否存在
if (array_key_exists('email', $user)) {
    echo "邮箱字段存在\n";
}

// 检查值是否存在
if (in_array('张三', $user)) {
    echo "值'张三'存在于数组中\n";
}

// 搜索值并返回键
$key = array_search(25, $user);
if ($key !== false) {
    echo "值25的键是: $key\n";
}

5.2 多维数组判断

$users = [
    'user1' => [
        'name' => '张三',
        'profile' => [
            'age' => 25,
            'city' => '北京'
        ]
    ]
];

// 安全访问多维数组
if (isset($users['user1']['profile']['age'])) {
    $age = $users['user1']['profile']['age'];
    echo "用户年龄: $age\n";
}

// 使用null合并运算符的链式调用(PHP 7+)
$city = $users['user1']['profile']['city'] ?? '未知';
echo "用户城市: $city\n";

六、文件系统判断:避免文件操作错误

6.1 文件存在性判断

$filename = 'config.php';

// 判断文件是否存在
if (file_exists($filename)) {
    echo "文件存在\n";
    
    // 判断是否为普通文件
    if (is_file($filename)) {
        echo "是普通文件\n";
    }
    
    // 判断是否为目录
    if (is_dir($filename)) {
        echo "是目录\n";
    }
    
    // 判断是否可读
    if (is_readable($filename)) {
        echo "文件可读\n";
    }
    
    // 判断是否可写
    if (is_writable($filename)) {
        echo "文件可写\n";
    }
    
    // 判断是否可执行
    if (is_executable($filename)) {
        echo "文件可执行\n";
    }
} else {
    echo "文件不存在\n";
}

6.2 文件上传判断

// 处理文件上传
if (isset($_FILES['avatar'])) {
    $uploadFile = $_FILES['avatar'];
    
    // 检查上传是否成功
    if ($uploadFile['error'] === UPLOAD_ERR_OK) {
        // 检查是否为上传文件(安全重要!)
        if (is_uploaded_file($uploadFile['tmp_name'])) {
            // 检查文件类型
            $allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
            if (in_array($uploadFile['type'], $allowedTypes)) {
                // 安全处理文件
                move_uploaded_file($uploadFile['tmp_name'], 'uploads/avatar.jpg');
            }
        }
    }
}

七、实战案例:完整的表单验证类

class FormValidator 
{
    public static function validateRegistration(array $data): array 
    {
        $errors = [];
        
        // 用户名验证
        if (!isset($data['username']) || empty(trim($data['username']))) {
            $errors['username'] = '用户名不能为空';
        } else {
            $username = trim($data['username']);
            if (!is_string($username)) {
                $errors['username'] = '用户名必须是字符串';
            } elseif (strlen($username) < 3) {
                $errors['username'] = '用户名至少3个字符';
            } elseif (strlen($username) > 20) {
                $errors['username'] = '用户名不能超过20个字符';
            }
        }
        
        // 邮箱验证
        if (!isset($data['email']) || empty(trim($data['email']))) {
            $errors['email'] = '邮箱不能为空';
        } else {
            $email = trim($data['email']);
            if (!is_string($email)) {
                $errors['email'] = '邮箱必须是字符串';
            } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $errors['email'] = '邮箱格式不正确';
            }
        }
        
        // 年龄验证
        if (isset($data['age'])) {
            if (!is_numeric($data['age'])) {
                $errors['age'] = '年龄必须是数字';
            } else {
                $age = (int)$data['age'];
                if ($age < 0 || $age > 150) {
                    $errors['age'] = '年龄必须在0-150之间';
                }
            }
        }
        
        // 兴趣验证(数组验证)
        if (isset($data['interests'])) {
            if (!is_array($data['interests'])) {
                $errors['interests'] = '兴趣必须是一个数组';
            } elseif (count($data['interests']) > 5) {
                $errors['interests'] = '兴趣不能超过5个';
            }
        }
        
        return $errors;
    }
}

// 使用示例
$formData = [
    'username' => '张三',
    'email' => 'zhangsan@example.com',
    'age' => '25', // 字符串形式的数字
    'interests' => ['编程', '阅读', '运动']
];

$errors = FormValidator::validateRegistration($formData);

if (empty($errors)) {
    echo "表单验证通过!\n";
} else {
    echo "验证错误:\n";
    print_r($errors);
}

八、性能优化与最佳实践

8.1 判断顺序优化

// 性能较差的写法
if (is_array($data) && count($data) > 0) {
    // 先判断类型,再判断长度
}

// 性能更好的写法
if (!empty($data) && is_array($data)) {
    // empty()对于非数组返回false,利用短路求值
}

// 实际性能测试对比
$testData = [];
$iterations = 1000000;

// 测试1:先is_array再count
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
    if (is_array($testData) && count($testData) > 0) {
        // 空操作
    }
}
$time1 = microtime(true) - $start;

// 测试2:先empty再is_array
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
    if (!empty($testData) && is_array($testData)) {
        // 空操作
    }
}
$time2 = microtime(true) - $start;

echo "方法1耗时: {$time1}秒\n";
echo "方法2耗时: {$time2}秒\n";

8.2 使用匹配函数提高可读性

// 复杂的条件判断
if (($status === 'active' && $role === 'admin') || 
    ($status === 'pending' && $role === 'editor') ||
    ($status === 'active' && $permissions['can_access'])) {
    // 复杂的条件逻辑
}

// 使用匹配函数提高可读性
function canAccess($status, $role, $permissions) {
    return match(true) {
        ($status === 'active' && $role === 'admin') => true,
        ($status === 'pending' && $role === 'editor') => true,
        ($status === 'active' && $permissions['can_access']) => true,
        default => false
    };
}

if (canAccess($status, $role, $permissions)) {
    // 清晰的逻辑
}

九、常见坑点及解决方案

9.1 strpos函数的0值问题

// 经典错误
$text = "Hello world";
if (strpos($text, 'Hello')) {
    // 这里不会执行!因为strpos返回0,0在条件判断中视为false
    echo "找到Hello\n";
}

// 正确写法
if (strpos($text, 'Hello') !== false) {
    echo "找到Hello\n"; // 这会执行
}

9.2 自动类型转换的陷阱

// 令人困惑的比较结果
echo "陷阱比较:\n";
echo "'0' == false: " . ('0' == false ? 'true' : 'false') . "\n"; // true
echo "'' == false: " . ('' == false ? 'true' : 'false') . "\n"; // true
echo "0 == false: " . (0 == false ? 'true' : 'false') . "\n"; // true
echo "null == false: " . (null == false ? 'true' : 'false') . "\n"; // true

// 解决方案:始终使用严格比较
echo "\n严格比较:\n";
echo "'0' === false: " . ('0' === false ? 'true' : 'false') . "\n"; // false
echo "0 === false: " . (0 === false ? 'true' : 'false') . "\n"; // false

十、总结:PHP判断函数的最佳实践

  1. 变量检查:优先使用 isset() 检查存在性,empty() 检查是否为空值
  2. 类型安全:始终使用 ===!== 进行严格比较
  3. 字符串操作:PHP 8+ 项目优先使用 str_contains() 等新函数
  4. 数组访问:使用 array_key_exists() 或 null合并运算符安全访问
  5. 性能优化:利用短路求值特性,合理安排判断顺序
  6. 代码可读性:复杂条件判断封装成函数或使用match表达式

记住: 好的判断逻辑是程序稳定性的基石。每次严谨的判断,都是在为代码质量投资!