记录PHP8.2、Mysql5.6之后主要升级的代码部分,以实现动态属性,对象引用防止重载警告和group数据调用

发布时间:2024年01月09日
  • PHP8.2后,动态属性将被弃用,而多年前在开发php框架时需要根据调用内容来生成动态属性,该这么办呢?
  • PHP4时代对象引用使用&,PHP5之后对象是引用传递,因为框架开发比较早,当时为了适配,运用了&符号,而升级到8之后会提示重载了;
  • Mysql5.6之后使用GROUP BY子句对数据进行分组,但在SELECT列表中包含了未被分组的非聚合列,那么将提示Fatal error: Syntax error or access violation: 1055 Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column

PHP部分

1. 动态属性

原本直接写

class A{
	public function setValue(){
		$this->num = 1;
	}
}

这里的num属性正规写,就必须要

class A{
	public $num;
	public function setValue(){
		$this->num = 1;
	}
}

同样,实例化后原本直接写即可

class A{
	public function setValue(){
		$this->num = 1;
	}
}

$x = new A();
$x->num = 1;

但现在升级为8.0以后还这样写,就会出现警告提示PHP Deprecated: Creation of dynamic property A::$num is deprecated in ...,而且未来该写法将被放弃。

那么我们就要利用魔术方法将所谓的动态属性写给一个数组来解决这个问题。

class A{
	private $_dynamicProperty = array();

	public function __get($name) {
		//判断是否存在该属性对应键名
        if (array_key_exists($name, $this->_dynamicProperty)) {
            return $this->_dynamicProperty[$name];
        }		
		return NULL;
    }
	
	//写入数组,属性名即为数组键名
    public function __set($name, $value) {
    	//将原本的属性名写入数组键名,调用的时候利用__get()方法直接去数组里获取
        $this->_dynamicProperty[$name] = $value;
    }

	//属性都存储在_dynamicProperty中,那么各应用模块中如果要用到isset时就需要调用本魔术方法
	//否则类似isset($obj->num)的操作去判断属性是否存在将会失败
	public function __isset($name) {
        return isset($this->_dynamicProperty[$name]);
    }
}

$x = new A();
$x->num = 1;

2. 对象引用和重载错误

重载指多个名字相同,但参数不同的函数在同一作用域并存的现象。因为PHP早期以灵活著称,所以传统意义上的重载将可能导致不同函数的覆盖从而出错。

我这里举例主要针对的是自研框架的错误。
当时开发框架时处于php4和php5期间,而php4重复同一个对象的操作需要用到&来作为引用,而到了php5,对象就是引用方式来使用的。以往用&符号引用对象不会有问题,但是到了php8之后,由于动态属性的已经变异了,那么再用&符号去引用就显得多余并且会出错了。
考虑到现在已经不需要再兼容PHP4了,所以我们的代码用PHP5及目前版本8.0都能接受的方式来重改。

解决办法很简单:那就是去掉&即可~~哈哈,就是这么简单。

原代码:

class A{
	public $num;
	public function setValue($n=0){
		$this->num = $n;
	}
}

$x = new A();
$y = & $x;
$y->setValue(5);
echo $y->num;
echo $x->num;

//结果
// 5
// 5

现改为:

class A{
	public $num;
	public function setValue($n=0){
		$this->num = $n;
	}
}

$x = new A();
$y = $x;
$y->setValue(5);
echo $y->num;
echo $x->num;

// 结果
// 5
// 5

《PHP对象赋值给变量的两种方式的区别,一般赋值和引用赋值?》
这里有一个小知识:加了&,就是对该变量的引用,没有加则还是对象的引用,如下案例:

class A{
	public $num;
	public function setValue($n=0){
		$this->num = $n;
	}
}

$x = new A();
$y = $x;
$z = & $x;
$y->setValue(5);
echo $y->num;
echo $x->num;
echo $z->num;

// 结果
// 5
// 5
// 5

// 此刻原本对象引用的变量$x的值改为null,那么引用它的$z的值也改变了,而$y因为是引用的对象,其值没有改变
$x = null;
var_dump($y);
var_dump($x);
var_dump($z);

// 结果
// object(A)#24 (1) { ["num"]=> int(5) }
// NULL
// NULL

这篇文章 《PHP的stdClass的理解》 虽然是针对基类的学习,但其中提到了对象的引用,可以学习。

参考:
《PHP:对象和引用》
《PHP重载》

Mysql部分

因group聚合产生的错误

错误警告类似于:

PHP Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘test.c.papername’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by in …

错误原因:

  • 使用了 GROUP BY 子句对数据进行分组,但在 SELECT 列表中包含了未被分组的非聚合列 test.c.papername。
  • 数据库模式设置为 sql_mode=only_full_group_by,该模式要求在 GROUP BY 子句中列出的列必须是所有非聚合列的函数依赖。

解决方案:

  1. 添加列到 GROUP BY 子句:
    test.c.papername 等涉及到的所有列添加到 GROUP BY 子句中,确保所有非聚合列都参与分组。
SELECT c.papername, COUNT(*) AS count
FROM paper as c
JOIN papercategory AS b ON c.id=b.id
...
GROUP BY b.categoryid //原本必须要整合的字段
GROUP BY c.papername, //SELECT中提到
GROUP BY c.paperid, // ORDER中提到
GROUP BY ...  // 添加其他分组列
...
ORDER BY c.paperid
  1. 使用聚合函数:
    如果不想在 GROUP BY 子句中包含 test.c.papername,可以使用聚合函数(如 MAX、MIN、SUM、AVG)来处理它:
SELECT MAX(c.papername) AS papername, COUNT(*) AS count
FROM paper as c
JOIN papercategory AS b ON c.id=b.id
...
GROUP BY b.categoryid //原本必须要整合的字段
  1. 调整 sql_mode:
    如果不想遵循 only_full_group_by 模式的严格要求,可以调整数据库的 sql_mode 设置:

在 MySQL 配置文件(my.cnf 或 my.ini)中找到 sql_mode 选项,并将 ONLY_FULL_GROUP_BY 从列表中移除。

或者,在 MySQL 会话中使用以下命令:

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
  1. 注意:
    调整 sql_mode 可能会影响其他 SQL 语句的行为,因此请谨慎操作,并在测试环境中进行验证。
    通常建议遵循 only_full_group_by 模式的规范,以确保数据的一致性和完整性。
    请根据您的具体查询和需求选择合适的解决方案。如果您可以提供更多代码或信息,我会更准确地帮助您解决问题。

  2. 结论:
    我选择了第一种方案,宁可吃力点,把所有因涉及到group而出错的代码给改了,
    第二种方案有隐患,参考《聊聊MySql8.0中的group by 和 max函数取最新(优)一条记录的问题》
    第三种方案万一服务器数据库不给修改就不好弄了,而且每次装机都可能涉及到修改数据库默认数值,这对于一个框架来说是不可取的。

文章来源:https://blog.csdn.net/snans/article/details/135483770
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。