PHP类的经典代码审查

类通过将其分解为较小的组件来帮助组织代码,将其组合在一起以构建强大的应用程序。属性定义,抽象类,局部变量和相同的方法是所有代码闻,可直接在具有许多类的大型存储库内发展。 

在这里,一些常见的代码闻名oOP PHP代码中出现的味道。它们都可以用exakat发现,静态分析发动机用于PHP。 

定义所有属性

PHP常见是灵活的,无需在使用之前声明属性。 

然而,它有助于PHP提前了解将使用属性。它通过预先分配内存来利用它,并更快地重用它。物业一旦需要就准备好。将其与退回行为进行比较,其中PHP必须搜索属性,未找到它,然后分配内存。这也有助于重用内存以用于新对象,因为它们现在具有可比和可预测的占用空间。 

快速基准将显示定义的属性比未定义的属性快50%。它是一种微观优化,因为访问属性非常快,但鉴于属性的使用量,包括在循环中,这通常是值得的。 

作为一个共同规则,确保所有的 属性定义。作为侧面笔记,它还可以帮助您的分析工具。

事实上,作为额外的提示,您可以将以下__get()和__set()添加到所有类中,包括完全定义和尚未使用的类’t使用魔术功能。与他们一起,当在执行期间调用一个未知的财产时,称为魔术方法,并将充当大公范,以警告您的窗体或错误目标。在开发和测试阶段使用它们,然后将它们删除为生产。 

<?php

trait NoUnefinedProperties {
    function __get($name) {
        assert(false, "Attempt to read the $name property, on the class ".__CLASS__;
    }

    function __set($name, $value) {
        assert(false, "Attempt to read the $name property, on the class ".__CLASS__;
    }
}

?>

可能是抽象课

一个抽象的班级是一个可以的课程’要实例化。它必须是一个具体课程的父母,可以实例化。除了持有静态方法和阶级常量外,这是它有用的唯一选择。 

那么你如何称呼延长,从未直接实施的课程?嗯,看起来像继承类的模板,实际上可能会被标记为 使用抽象的关键字

<?php

// This class is never instantiated
class Money {
    function __construct() { }  
}

class Euro   extends Money {}
class Dollar extends Money {}
class Yuan   extends Money {}


?>

这实际上将阻止要实例化的类,但具有构造函数。请注意,不需要任何摘要的方法:整个类可能是抽象的,实现接口,但尚无抽象的方法。

抽象班赢了’t至少直接测试。当您想要保留这些测试时,将此抽象类扩展为空的混凝土级。然后,测试此类。行为是相同的,但现在,有一个特殊的类,与任何实现不同。 

<?php

// This class is tested with Rawmoney
abstract class Money {
    function __construct() { }  
}

class Euro     extends Money { /* more code */ }
class Dollar   extends Money { /* more code */ }
class Yuan     extends Money { /* more code */ }
class Rawmoney extends Money {}

?>

财产可能是当地的

属性与局部变量之间的家庭关系是什么?两者都可以保持值,但范围是不同的。局部变量仅限于方法范围,而在课程中可以在课程中提供属性(让’s省略了一会儿的公共属性)。

<?php

// This class is tested with Rawmoney
class Foo {
    private $property = 1;
    private $property2 = 1;
    
    function Bar($arg) {
        $this->property = $arg + 4 + $this->property2;
        $this->property2 = $this->property * 2;
    }   
    
    function BarBar() {
        return $this->property2;
    }
}

?>

使用这些定义,局部变量和属性类似但不同。事实上,它们是相同的唯一时刻是它们累积约束时:a 仅在一种方法中使用的属性

此类属性可以变成局部变量,而不会影响班级的其余部分。 

可以在多个调用中使用该属性以相同的方法:在这种情况下,将其移动到静态变量可能很有意思。 

还有另一个有趣的情况:一个有多种方法可用的局部变量。为此,本地范围必须通过将其他方法称为参数来将局部变量传输到另一个范围。这是本地开始的变量在多种方法中出现,直到一个实现它可以升级到属性,然后从这些签名中删除。

类树中的相同方法

通常在一个类中发现相同的方法通常是:名称本身通常足以产生« Fatal error »。另一方面, 类中的相同方法 树更难找到。

那是,对我们来说,更难以找到人类。在父类和儿童类中提供的相同方法奇怪地难以解决。它们看起来相同,而且它们也属于不同的文件,同时服务相同的目的。如果一个人覆盖另一个,那可能是运气不好。

<?php

// This class is tested with Rawmoney
class Foo {
    protected function bar() { /**/ }
}

class Foo2 extends Foo {
    // Same as above
    protected function bar() { /**/ }
    protected function barfoo() { /**/ }
}

?>

类树中的相同方法是复制/粘贴代码气味。其中一个类是在其创建期间从另一个复制,或者一些概括的重构停止了短,并且在多个位置处左侧方法。 

良好的方面是,静态分析很容易找到它们。只要它们相同,而不是修改。 

剩余方法的选择可能是棘手的:它是一种父方法,可供其他孩子吗?还是是孩子的具体方法?甚至,如果孩子方法故意覆盖父母,请取消呢? 

可以使用自我

通常,类别以完全合格的名称识别,例如 \X\A\B\C\MyClass,甚至是别名 MyClass。就像硬件的任何事情一样,很难改变它而不重构其所有情况。 

<?php

// This class is tested with Rawmoney
class Foo {
    protected const A = 1;
    
    function bar() {
        // Static FQN
        return Foo::A;

        // Adaptable FQN
        return self::A;

        // For LSB users
        return static::A;
    }
}

?>

每当类别用FQN引用自己, 特殊名称‘self’ (或它关闭表姐‘static’对于晚期末期约束力,应使用。它保持FQN相对于类,仍然是可读的。它使任何重构或重命名更容易。 

请注意,Self也代表任何父类,因此即使在引用父母中定义的结构时也可以使用它。 

<?php

// This class is tested with Rawmoney
class Foo {
    protected const A = 1;
}

class FooBar extends Foo {
    function bar() {
        // Return Foo::A
        return self::A;

        // For LSB users : here, self === static
        // as A is defined above only
        return static::A;
    }
}

?>

断开连接的课程

让 ’完成特殊结构的结束: 断开连接的课程。当一个类扩展另一个类时,这会发生在课程层次结构中。情况是,这两个课程都保持生活,分开:他们从不打电话给另一个。

<?php

class Foo {
    protected const A = 1;
}

class FooFoo extends Foo {
    function bar() {
        return 1;
    }
}

?>

一个极端情况是父类为子类提供支持时。这通常会保存重复代码,提供正式的结构,并帮助将儿童类插入更大的框架。在这种情况下,子类利用父类。 

另一个极端情况是当父类充当儿童类的模板时,它提供专门化,例如方法或属性。父父具有一些通用代码,它归功于子配置。父类调用孩子。

常规情况是上面两个的混合版本,其中父和儿童互相呼叫。最后,这构建了一个集成的类,这是两个初始类的微妙组合。这几乎听起来像遗传学。

<?php

abstract class Foo {
    protected const A = 1;

    function foo2() {
        return $this->bar();
    }
    
    abstract function bar();
}

class FooFoo extends Foo {
    function bar() {
        return self::A;
    }
}

?>

那么,当两个课程有一个延伸关系时会发生什么,但是互相召唤?这是一个代码嗅觉,其中一个课程试图在代码的错误地方履行任务。重构是一种良好的开始。

快乐的代码评论

大多数模式都发生了代码的有机演变。它们是代码审查首先重要的原因:在类中或控制流程中读取代码库和点奇怪构造需要一些经验和时间。

所有这些错误都可用‘课堂评论‘规则集,在exakat引擎中。 exakat. 是一个静态分析工具,可查看代码质量和自我改进的PHP代码。它是 开源, 便于 安装 并可能在任何PHP代码库上运行。