一个原来的项目,因为业务需要,进行了PHP版本升级,从php5.3直接升级到php8.3。变化挺大的,原程序中有很多不再兼容,在此处进行一下记录。
一、Deprecated: 显式转换问题
报错内容:Deprecated: Implicit conversion from float 173387987633874.1 to int loses precision in
之前运行正常的一段代码(印象中还是原百度公司中生成日志的一个方法),切换PHP环境从5.3至8.3时报了些错误,因为是很久前的代码了,我就简单看了一下并作一下记录。
private function __initLogID()
{
if(defined('LOG_ID')) return LOG_ID;
$arr = gettimeofday();
$t = ($arr['sec']*100000 + $arr['usec']/10) & 0x7FFFFFFF;
define('LOG_ID', $t);
return LOG_ID;
}
这个PHP警告是关于隐式转换的。在PHP 7及以上版本中,当将一个浮点数(float)转换为整数时,如果不显式指定转换类型,PHP会进行截断操作,即直接去掉小数点后的数字,而不是四舍五入。如果转换后的整数超出了整数的表示范围,PHP会发出一个警告信息。
报错中的数字173387987633874.1被隐式转换成了173387987633874,这个数字在转换过程中没有超出整数的范围,但在后续的代码中可能会导致不正确的行为。
所以解决方法就是:进行显式转换类型:使用intval()或(int)来进行强制转换,并指定正确的进制,如下即可。
$t = intval($arr['sec']*100000 + $arr['usec']/10) & 0x7FFFFFFF;
二、Deprecated: 动态属性问题
Deprecated: Creation of dynamic property XXXController::$xxx is deprecated in
底层程序框架中有很多地方使用了动态属性的设置,这是PHP的一个很好用的功能。动态属性是 PHP 元编程的重要组成部分——许多框架都依赖它!
/***********************************
全局核心设置方法
***********************************/
public function __set($key, $value)
{
$this->$key=$value;
}
不过版本升级以后,发现在 PHP 8.2对这个进行了弃用。特别是弃用了这个动态属性。什么是动态属性?就是直接给类定义不存在的属性,但在运行时动态设置在这些类的对象上。自 PHP 8.2 起,这个动态属性被弃用。
不过呢,也不要气馁。对类进行 __get并且__set仍然有效!所以呢,不用担心。增加一些方法,可以使这个新的弃用不会影响任何实现__get 和类 __set。
class Test
{
private array $properties = [];
public function __set(string $name, mixed $value)
{
$this->properties[$name] = $value;
}
}
当然,此处进行了修改之后,也需要对 __get 进行适应的修改,才能正常运行。代码我就不贴了,一看就懂。
三、Deprecated: key方法过时
报错内容:Deprecated: key(): Calling key() on an object is deprecated
在PHP中,当你尝试使用key()函数来获取数组中当前元素的键名,但是你传递给key()的参数是一个对象时,会触发这个已废弃(deprecated)的警告。从PHP 7.2开始,调用key()在对象上是不支持的,并且会引发此类警告。
public static function __getSlientDB()
{
//原方法
//return key(self::$__config);
//使用如下方法替代
return current(array_keys(get_object_vars(self::$__config)));
}
在PHP 8中,可使用get_object_vars函数来获取对象的所有属性。这个函数返回一个数组,包含对象中所有可访问的属性和它们的值。上面就可以使用此方法替换已过期的 key 方法。
三、Fatal error:
Fatal error: Uncaught TypeError: Attribute value must be of type int for selected attribute, string given 代码如下:
private static $errmode='PDO::ERRMODE_WARNING';
private function initDb()
{
$this->initTime();
$db = new PDO(self::$db_dsn, self::$db_username, self::$db_password, self::$db_dotype);
$db->query(self::$db_querychar);
// 此处的 PDO::ERRMODE_WARNING 原为设置的$errmode属性值,用的字符串形式
// 修改为直接使用 PDO::ERRMODE_WARNING,也可将第一行属性去除引号即可
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
KeDebug::dblog("Link Database {$this->__dbResourceName}.", $this->calculateTime(), $this->__dbResourceName);
return $db;
}
PDO::ERRMODE_WARNING 原为设置的一个属性值,用的字符串形式。在原版本中都能正常,升级后的 php8中,报语法错误类型不对,因此直接使用 。
四、call_user_func_array问题
php8 call_user_func_array Uncaught Error: Unknown named parameterParse error:
原框架在调用 call_user_func_array 的时候传递的 数组参数能正常运行,但在php8.3 中,发现会报错,推测是要求函数中必须要有相关的参数定义,于是在 call_user_func_array 调用的方法上加上了与后面传递的数组参数相同名称的参数名,错误就解决了。