PHP 类的一个疑问

2015-06-14 11:58:07 +08:00
 iyaozhen

我有一个类,几个方法都需要用到其它一个加解密类。

我是实例化一次然后用个变量(类的属性)存起来还是每次需要时再实例化好?

其实我是不太明白

require("class.php");   // 把可能需要的文件都在构造函数中 require 会影响性能吗?
new class();

两步发生了什么?

3553 次点击
所在节点    PHP
16 条回复
laoyuan
2015-06-14 12:06:19 +08:00
PHP 请求之间是独立的
shuimugan
2015-06-14 12:09:06 +08:00
可以写把你的类写成单例模式(就是不能直接new,在类的方法里new,只new一次),或者把加解密函数写成静态函数(不需要new,以 类::函数() 的方式调用)
require 的说明http://php.net/manual/zh/function.require.php
raincious
2015-06-14 12:10:01 +08:00
呵呵。

你要是多次require的话,应该会提示redeclared class(之类)。最好用一个Autoloader来自动require,因为每次用一个Class的时候,PHP会检查这个Class是不是已经载入了,这样就不存在require冲突的问题了。(require_once是一个解法,但不是最优的)

另外至于是不是要new一个加密Class:
1、如果你的consturctor操作比较多,比较慢,或者根本没必要多次new,那么建立一个Singleton就好了。(protected/private construct,然后建立一个public static方法在内部new好,再缓存new出来的Instance)
2、如果你的consturctor操作不多,且Class中的数据需要用不同的Instance隔离,那么就必须new。
loveyu
2015-06-14 12:10:05 +08:00
性能基本无影响,就是这样玩的。
zakokun
2015-06-14 12:10:51 +08:00
单例
zakokun
2015-06-14 12:11:25 +08:00
@zakokun 单例模式或者干脆静态类都可以。
timsims
2015-06-14 12:25:27 +08:00
单例是反模式,不方便测试

楼主的意思,我的理解是: A类内有若干个方法需要调用B类

那么可以使用依赖注入,先把B类实例化后,作为参数传给A类的构造函数里

Class A
{
protected $bClass;

public function __construct(B $bClass)
{
$this->$bClass = $bClass;
}

public function someMethod()
{
$this->$bClass->method();
}
}

class B
{
public function method(){}
}

$b = new B;
$a = new A($b);
iyaozhen
2015-06-14 12:32:50 +08:00
@shuimugan @zakokun 谢谢,单例模式、静态类是个好方法。

@raincious 没多次 require,这个我有注意。谢谢指点,其实我现在多不多次 new 都行。只是一直不明白 new class() 这一步底层发生了什么(当构造函数什么都没做的情况下)?
ab
2015-06-14 12:34:59 +08:00
菜鸟问一下,为什么不include
iyaozhen
2015-06-14 12:41:29 +08:00
@timsims 嗯嗯,就是这个意思。其实我现在做法是这样:
Class A
{
protected $bClass;

public function someMethod1()
{
$this->$bClass = new B();
$this->$bClass->method1();
// $tmp = new B();
// $tmp->method1();
}

public function someMethod2()
{
$this->$bClass->method2();
// $tmp = new B();
// $tmp->method2();
}
}

class B
{
public function method1(){}
public function method2(){}
}

因业务逻辑关系 someMethod1() 一定在 someMethod2() 前面调用。
注释里面的是每次都 new 的情况。

主要疑问就是 $this->$bClass 存着实例化的 class B 有什么坑吗?(class B 就是加解密,CPU 运算,没有涉及到 IO)
iyaozhen
2015-06-14 12:46:04 +08:00
@ab 因为是必须要引入的库,没引入的话流程进行不下去,所以用了 require。

require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误,换句话说将导致脚本中止。而 include 只产生警告(E_WARNING),脚本会继续运行。
timsims
2015-06-14 13:04:16 +08:00
@iyaozhen

实例化本身不存在什么坑,但是在类中去实例化对象就存在耦合问题(你这里就是A类的方法中new B),假如有一天你想把项目里所有class B都替换成class C,那就相当麻烦,这就是为什么我推荐通过依赖注入在A的构造函数里传入实例化后的B

不过我那个例子其实还不是最优的,最优的做法应该是注入一个接口,让B实现这个接口

具体还是看用代码说明。。

```
Interface WhatEver
{
public function method1();
public function method2();
}

Class A
{
protected $bClass;

public function __construct(WhatEver $bClass)
{
$this->bClass = $bClass;
}

}

class B implements WhatEver
{
public function method1(){}
public function method2(){}
}

class C implements WhatEver
{
public function method1(){}
public function method2(){}
}

$b = new B();
$a = new A($b);

// 有一天你想把B无痛替换成C
$c = new C();
$a = new A($c); // 就这么简单
```
raincious
2015-06-14 13:08:28 +08:00
@iyaozhen

PHP干了啥,这你得探索下源代码了。

当然,语言的用户(PHP程序员)而言,如果不考虑构造函数的消耗,那么new一个对象的消耗是十分低的,你可以自己做个测试,让PHP建立上万个对象然后看看总耗时。

除非对象太多(取决于你的可用内存)可能会出现GC效能下降的问题(参见Composer那次),但就这个问题来说应该不会可能与到。
hitsmaxft
2015-06-14 13:16:38 +08:00
由于 php 的源代码(加载后编译成 opcode)在fpm 模式下,也算是资源而已。所以每次请求都不得不重新加载 class 所在的源代码。


在性能开销上考虑的话,可以引入 opcache 缓存扩展, 比如 zend opcache (5.5内置, 5.3和5.4 需要自行编译, apc 等其他老扩展的真心不推荐)

另外, 用 require 和 include 差别不大, 这种关键代码无论如何都不应该加载失败的。但注意 _once 系列函数别用。 至少在 apc 下是有 bug 的,这种函数是玩玩用的。

按需 new 或者单例,取决于这个实例的创建成本。这部分 @raincious 已经解释了

其实你的问题关键点不在 include , 而在 new XXclass() ; 会触发 查找类和调用 autoload 等等流程。

new XXX() -> XXX 不存在? -> 触发 autoload -> 类存在了?调用构造器 : 继续调用其他autoloader -> 还是没找到? 抛出异常
iyaozhen
2015-06-14 13:23:28 +08:00
@timsims 谢谢,耦合问题没注意到。

@raincious 谢谢。自己应该多试试。
hahamy
2015-06-14 14:07:20 +08:00
如果class B有内在的逻辑,那么每次new B都是生成新的对象实例,相互之间不会影响,单例上一次对对象的操作,仍保留在对象内,下次调用的还是这个对象,所以看B的逻辑来做选择

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/198418

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX