PHP 类的一个疑问 - V2EX
iyaozhen
V2EX    PHP

PHP 类的一个疑问

  •  
  •   iyaozhen Jun 14, 2015 4125 views
    This topic created in 4009 days ago, the information mentioned may be changed or developed.

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

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

    其实我是不太明白

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

    两步发生了什么?

    16 replies    2015-06-14 14:07:20 +08:00
    laoyuan
        1
    laoyuan  
       Jun 14, 2015
    PHP 请求之间是独立的
    slowgen
        2
    slowgen  
    PRO
       Jun 14, 2015   1
    可以写把你的类写成单例模式(就是不能直接new,在类的方法里new,只new一次),或者把加解密函数写成静态函数(不需要new,以 类::函数() 的方式调用)
    require 的说明http://php.net/manual/zh/function.require.php
    raincious
        3
    raincious  
       Jun 14, 2015   2
    呵呵。

    你要是多次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
        4
    loveyu  
       Jun 14, 2015   1
    性能基本无影响,就是这样玩的。
    zakokun
        5
    zakokun  
       Jun 14, 2015
    单例
    zakokun
        6
    zakokun  
       Jun 14, 2015   1
    @zakokun 单例模式或者干脆静态类都可以。
    timsims
        7
    timsims  
       Jun 14, 2015   1
    单例是反模式,不方便测试

    楼主的意思,我的理解是: 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
        8
    iyaozhen  
    OP
       Jun 14, 2015
    @shuimugan @zakokun 谢谢,单例模式、静态类是个好方法。

    @raincious 没多次 require,这个我有注意。谢谢指点,其实我现在多不多次 new 都行。只是一直不明白 new class() 这一步底层发生了什么(当构造函数什么都没做的情况下)?
    ab
        9
    ab  
       Jun 14, 2015
    菜鸟问一下,为什么不include
    iyaozhen
        10
    iyaozhen  
    OP
       Jun 14, 2015
    @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
        11
    iyaozhen  
    OP
       Jun 14, 2015
    @ab 因为是必须要引入的库,没引入的话流程进行不下去,所以用了 require。

    require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误,换句话说将导致脚本中止。而 include 只产生警告(E_WARNING),脚本会继续运行。
    timsims
        12
    timsims  
       Jun 14, 2015   1
    @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
        13
    raincious  
       Jun 14, 2015   1
    @iyaozhen

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

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

    除非对象太多(取决于你的可用内存)可能会出现GC效能下降的问题(参见Composer那次),但就这个问题来说应该不会可能与到。
    hitsmaxft
        14
    hitsmaxft  
       Jun 14, 2015   1
    由于 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
        15
    iyaozhen  
    OP
       Jun 14, 2015
    @timsims 谢谢,耦合问题没注意到。

    @raincious 谢谢。自己应该多试试。
    hahamy
        16
    hahamy  
       Jun 14, 2015   1
    如果class B有内在的逻辑,那么每次new B都是生成新的对象实例,相互之间不会影响,单例上一次对对象的操作,仍保留在对象内,下次调用的还是这个对象,所以看B的逻辑来做选择
    About     Help     Advertise     Blog     API     FAQ     Solana     2857 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 73ms UTC 14:01 PVG 22:01 LAX 07:01 JFK 10:01
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86