PHP Cannot use assign-op operators with string offsets | Illegal string offset

探讨PHP5.4中处理字符串偏移时的常见错误,如使用非数字索引时isset和empty的行为变化,及如何通过初始化解决警告问题。

描述PHP Cannot use assign-op operators with string offsets | Illegal string offset

PHP5.4中一个需要注意的变化(Chained string offsets) , 这个坑容易被踩到;
描述:当对于一个变量name,如果name, 如果name,name是一个字符串, 那么, 对于非数字型索引, 比如name[′age′],在isset的时候将返回false,empty返回true,但是为了兼容已有的代码,当你获取这个值的时候,还是会返回name['age'], 在isset的时候将返回false, empty返回true, 但是为了兼容已有的代码, 当你获取这个值的时候, 还是会返回name[age],issetfalse,emptytrue,,,name[0], 不过会额外抛出一个警告信息.

$name = "leyangjun";
var_dump($name["age"]);
//输出:string(1) "l"  -->(同时会有个警告(非法字符串偏移量):Warning: Illegal string offset 'age' in /usercode/file.php on line 3)


//而键值是bool, double, null的情况, 将会和以前保持一致, 不过会抛出一个Notice信息.
var_dump(isset($name["age"]));//输出:false
var_dump(empty($name["age"]));//输出:true

项目实际例子

if (!empty($polymerizeData)) {
    foreach ($polymerizeData as $rKey => $rVal) {
        foreach ($rVal as $iKey => $iVal) {
            $ret[$rKey]['submit_date'] = date('Y-m', time()));
            $ret[$rKey]['wx_amount'] += $iVal['wx_amount'] / 100;
            $ret[$rKey]['alipay_amount'] += $iVal['alipay_amount'] / 100;

			//$iVal['google_play_amount'],存储的是个json
            $googlePlayAmount = json_decode($iVal['google_play_amount'], true);
            if (!empty($googlePlayAmount)) {
                foreach ($googlePlayAmount as $gKey => $gVal) {
                    //此处:会抛出一个waring -->{\"code\":0,\"message\":\"Cannot use assign-op operators with string offsets\",\"file\":\"\\/leyangjun\\/Applications\\/leyangjun.php\",\"line\":67"}
                    $ret[$rKey]['google_play_amount'][$gKey] += $gVal;
            }
        }
    }
}

解决办法,对数据类型做下初始化即可

if (!empty($polymerizeData)) {
    foreach ($polymerizeData as $rKey => $rVal) {
        foreach ($rVal as $iKey => $iVal) {
			$ret[$rKey]['google_play_amount'] = isset($ret[$rKey]['google_play_amount']) ? $ret[$rKey]['google_play_amount'] : [];//初始化默认值
            $ret[$rKey]['submit_date'] = date('Y-m', time()));
            $ret[$rKey]['wx_amount'] += $iVal['wx_amount'] / 100;
            $ret[$rKey]['alipay_amount'] += $iVal['alipay_amount'] / 100;

			//$iVal['google_play_amount'],存储的是个json
            $googlePlayAmount = json_decode($iVal['google_play_amount'], true);
            if (!empty($googlePlayAmount)) {
                foreach ($googlePlayAmount as $gKey => $gVal) {
                    $ret[$rKey]['google_play_amount'][$gKey] = (isset($ret[$rKey]['google_play_amount'][$gKey]) ? $ret[$rKey]['google_play_amount'][$gKey] : 0) +$gVal;
            } 
        }
    }
}

总结

由于PHP是个弱类型语言,在写代码逻辑时最好都做下严谨判断

/*---------------------------------------------------------------------- | AP4_String::EmptyString +---------------------------------------------------------------------*/ char AP4_String::EmptyString = 0; /*---------------------------------------------------------------------- | AP4_String::AP4_String +---------------------------------------------------------------------*/ AP4_String::AP4_String() : m_Chars(&EmptyString), m_Length(0) {} /*---------------------------------------------------------------------- | AP4_String::AP4_String +---------------------------------------------------------------------*/ AP4_String::AP4_String(const char* s) { if (s == NULL) { m_Chars = &EmptyString; m_Length = 0; return; } m_Length = (AP4_Size)AP4_StringLength(s); m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s, m_Length+1); } /*---------------------------------------------------------------------- | AP4_String::AP4_String +---------------------------------------------------------------------*/ AP4_String::AP4_String(const char* s, AP4_Size size) : m_Chars(new char[size+1]), m_Length(size) { m_Chars[size] = 0; AP4_CopyMemory(m_Chars, s, size); } /*---------------------------------------------------------------------- | AP4_String::AP4_String +---------------------------------------------------------------------*/ AP4_String::AP4_String(const AP4_String& s) { m_Length = s.m_Length; m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s.m_Chars, m_Length+1); } /*---------------------------------------------------------------------- | AP4_String::AP4_String +---------------------------------------------------------------------*/ AP4_String::AP4_String(AP4_Size size) { m_Length = size; m_Chars = new char[m_Length+1]; for (unsigned int i=0; i<size+1; i++) m_Chars[i] = 0; } /*---------------------------------------------------------------------- | AP4_String::~AP4_String +---------------------------------------------------------------------*/ AP4_String::~AP4_String() { if (m_Chars != &EmptyString) delete[] m_Chars; } /*---------------------------------------------------------------------- | AP4_String::operator= +---------------------------------------------------------------------*/ const AP4_String& AP4_String::operator=(const AP4_String& s) { if (&s == this) return s; if (m_Chars != &EmptyString) delete[] m_Chars; m_Length = s.m_Length; m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s.m_Chars, m_Length+1); return *this; } /*---------------------------------------------------------------------- | AP4_String::operator= +---------------------------------------------------------------------*/ const AP4_String& AP4_String::operator=(const char* s) { if (s == NULL) { if (m_Chars != &EmptyString) delete[] m_Chars; m_Chars = &EmptyString; m_Length = 0; } else { Assign(s, (AP4_Size)AP4_StringLength(s)); } return *this; } /*---------------------------------------------------------------------- | AP4_String::operator== +---------------------------------------------------------------------*/ bool AP4_String::operator==(const AP4_String& s) const { if (m_Length != s.m_Length) return false; for (unsigned int i=0; i<m_Length; i++) { if (m_Chars[i] != s.m_Chars[i]) return false; } return true; } /*---------------------------------------------------------------------- | AP4_String::operator== +---------------------------------------------------------------------*/ bool AP4_String::operator==(const char* s) const { AP4_Size s_length = (AP4_Size)AP4_StringLength(s); if (m_Length != s_length) return false; for (unsigned int i=0; i<s_length; i++) { if (m_Chars[i] != s[i]) return false; } return true; } /*---------------------------------------------------------------------- | AP4_String::Assign +---------------------------------------------------------------------*/ void AP4_String::Assign(const char* s, AP4_Size size) { if (m_Chars != &EmptyString) delete[] m_Chars; m_Length = size; m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s, m_Length); m_Chars[size] = '\0'; } /*---------------------------------------------------------------------- | AP4_String::Find +---------------------------------------------------------------------*/ int AP4_String::Find(char c, unsigned int start) const { const char* chars = GetChars(); for (unsigned int i=start; i<m_Length; i++) { if (chars[i] == c) return i; } return -1; } 注释上述代码
09-25
# AP4_String 类解析 ## 静态成员和基础构造函数 ```cpp /*---------------------------------------------------------------------- | AP4_String::EmptyString | 功能: 静态空字符串(用于空字符串表示) | 特性: | - 全局唯一的空字符串标记 | - 用于区分空字符串和NULL指针 +---------------------------------------------------------------------*/ char AP4_String::EmptyString = 0; /*---------------------------------------------------------------------- | AP4_String 默认构造函数 | 功能: 创建空字符串 | 初始化: | - m_Chars: 指向EmptyString(避免NULL指针) | - m_Length: 0(空字符串长度) +---------------------------------------------------------------------*/ AP4_String::AP4_String() : m_Chars(&EmptyString), m_Length(0) {} /*---------------------------------------------------------------------- | AP4_String 构造函数(C字符串) | 功能: 从C风格字符串创建AP4_String | 参数: | - s: 源C字符串指针 | 特性: | - 处理NULL指针情况(转为空字符串) | - 自动计算字符串长度 | - 分配独立内存并拷贝内容 +---------------------------------------------------------------------*/ AP4_String::AP4_String(const char* s) { if (s == NULL) { m_Chars = &EmptyString; m_Length = 0; return; } m_Length = (AP4_Size)AP4_StringLength(s); m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s, m_Length+1); } ``` ## 其他构造函数和析构函数 ```cpp /*---------------------------------------------------------------------- | AP4_String 构造函数(带长度参数) | 功能: 从指定长度的字符数组创建字符串 | 参数: | - s: 源字符数组指针 | - size: 要拷贝的字符数 | 特性: | - 显式指定长度避免依赖'\0'终止符 | - 自动添加字符串终止符 +---------------------------------------------------------------------*/ AP4_String::AP4_String(const char* s, AP4_Size size) : m_Chars(new char[size+1]), m_Length(size) { m_Chars[size] = 0; // 确保字符串终止 AP4_CopyMemory(m_Chars, s, size); } /*---------------------------------------------------------------------- | AP4_String 拷贝构造函数 | 功能: 深拷贝另一个AP4_String对象 | 特性: | - 完全独立的内存分配 | - 包括终止符在内的完整拷贝 +---------------------------------------------------------------------*/ AP4_String::AP4_String(const AP4_String& s) { m_Length = s.m_Length; m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s.m_Chars, m_Length+1); } /*---------------------------------------------------------------------- | AP4_String 构造函数(指定大小) | 功能: 创建指定大小的空字符串 | 参数: | - size: 字符串缓冲区大小 | 特性: | - 初始化所有字符为0 | - 实际可存储size个字符+终止符 +---------------------------------------------------------------------*/ AP4_String::AP4_String(AP4_Size size) { m_Length = size; m_Chars = new char[m_Length+1]; for (unsigned int i=0; i<size+1; i++) m_Chars[i] = 0; } /*---------------------------------------------------------------------- | AP4_String 析构函数 | 功能: 释放字符串内存 | 特性: | - 仅当不是指向EmptyString时才释放内存 | - 避免重复释放静态EmptyString +---------------------------------------------------------------------*/ AP4_String::~AP4_String() { if (m_Chars != &EmptyString) delete[] m_Chars; } ``` ## 运算符重载 ```cpp /*---------------------------------------------------------------------- | AP4_String::operator= (AP4_String版本) | 功能: 字符串赋值运算符(从另一个AP4_String) | 特性: | - 处理自赋值情况 | - 先释放旧内存再分配新内存 | - 深拷贝内容 +---------------------------------------------------------------------*/ const AP4_String& AP4_String::operator=(const AP4_String& s) { if (&s == this) return s; // 自赋值检查 if (m_Chars != &EmptyString) delete[] m_Chars; m_Length = s.m_Length; m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s.m_Chars, m_Length+1); return *this; } /*---------------------------------------------------------------------- | AP4_String::operator= (C字符串版本) | 功能: 字符串赋值运算符(从C字符串) | 特性: | - 处理NULL指针情况(转为空字符串) | - 自动计算字符串长度 | - 重用Assign方法实现 +---------------------------------------------------------------------*/ const AP4_String& AP4_String::operator=(const char* s) { if (s == NULL) { if (m_Chars != &EmptyString) delete[] m_Chars; m_Chars = &EmptyString; m_Length = 0; } else { Assign(s, (AP4_Size)AP4_StringLength(s)); } return *this; } ``` ## 比较运算符和工具方法 ```cpp /*---------------------------------------------------------------------- | AP4_String::operator== (AP4_String版本) | 功能: 字符串相等比较 | 策略: | 1. 先比较长度,不同则直接返回false | 2. 逐个字符比较 +---------------------------------------------------------------------*/ bool AP4_String::operator==(const AP4_String& s) const { if (m_Length != s.m_Length) return false; for (unsigned int i=0; i<m_Length; i++) { if (m_Chars[i] != s.m_Chars[i]) return false; } return true; } /*---------------------------------------------------------------------- | AP4_String::operator== (C字符串版本) | 功能: 与C字符串比较 | 特性: | - 自动计算C字符串长度 | - 比较逻辑与AP4_String版本一致 +---------------------------------------------------------------------*/ bool AP4_String::operator==(const char* s) const { AP4_Size s_length = (AP4_Size)AP4_StringLength(s); if (m_Length != s_length) return false; for (unsigned int i=0; i<s_length; i++) { if (m_Chars[i] != s[i]) return false; } return true; } /*---------------------------------------------------------------------- | AP4_String::Assign | 功能: 安全赋值方法 | 参数: | - s: 源字符串指针 | - size: 要拷贝的字符数 | 特性: | - 先释放旧内存 | - 分配精确大小的新内存 | - 确保字符串终止 +---------------------------------------------------------------------*/ void AP4_String::Assign(const char* s, AP4_Size size) { if (m_Chars != &EmptyString) delete[] m_Chars; m_Length = size; m_Chars = new char[m_Length+1]; AP4_CopyMemory(m_Chars, s, m_Length); m_Chars[size] = '\0'; // 确保终止 } /*---------------------------------------------------------------------- | AP4_String::Find | 功能: 查找字符首次出现位置 | 参数: | - c: 要查找的字符 | - start: 起始查找位置 | 返回值: | - 找到返回索引位置 | - 未找到返回-1 +---------------------------------------------------------------------*/ int AP4_String::Find(char c, unsigned int start) const { const char* chars = GetChars(); for (unsigned int i=start; i<m_Length; i++) { if (chars[i] == c) return i; } return -1; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值