这可能是一个基本问题,但它让我想了很长时间。
我应该声明所有私有/局部变量都是私有的吗?或者这仅对“重要”变量是必需的?
例如,我有一个计算的(临时)结果。我应该预先声明这个变量吗?
希望有人能指出这一点。
既然你在谈论private
,我认为你在谈论属性protected
,而不是变量。
在这种情况下:是的,您应该事先声明它们。public
由于 PHP 对象的设计方式,properties_table
在编译时会创建一个数组 ( )。该数组可确保尽可能快地访问给定属性。但是,如果您在进行过程中添加属性,PHP 也需要跟踪这一点。出于这个原因,一个对象也有一个简单的properties
表。
第一个 ( properties_table
) 是一个指针数组,而后者是一个简单的 key => value 表。
所以呢?好吧,因为properties_table
只包含指针(具有固定大小),所以它们存储在一个简单的数组中,并且使用它们各自的偏移量获取指针。偏移量存储在另一个哈希表中,即ce->properties_info
指针。
正如 bwoebi 在评论中向我指出的那样:获取偏移量(HashTable 查找)是最坏情况的线性运算(O(n)),而预定义的属性查找是常数时间复杂运算(O(1))。另一方面,动态属性需要另一个 HashTable 查找,即最坏情况的线性运算 (O(n))。这意味着,访问动态属性平均需要大约两倍的时间。不过,维基百科的作者可以比我更好地解释时间复杂性。
起初,访问修饰符似乎无关紧要。随着您的进行,您很快就会发现,有时您只是不想冒险某个对象的某些属性被一些代码修改。这时候你就看到了 的价值private
。
如果一个对象包含另一个对象,它包含您的代码将依赖的各种设置,例如,您可能会使用 getter 方法从外部访问这些设置,但您会将实际属性很好地隐藏起来使用private
.
如果更进一步,您要向您的项目添加数据模型和服务层,那么您将编写一个(抽象)父类,如果只是用于类型提示的话,这是一个很好的改变。
如果这些服务实例包含类似配置属性的东西,您可能会在父类中定义该 getter(只定义一次)。private
意味着只有当前类可以访问属性,但是由于您不会使用父级的实例,而是子级的实例,因此您会看到为什么protected
在处理较大的项目时是无价的,也。
就临时变量而言,无论是在方法、函数还是其他任何地方,您都不必预先声明它们,但在某些情况下数组除外:
public function foo()
{
$temp = $this->getSomeValue();
return $temp ? $temp +1 : null;
}
是完全有效的,如果你要写就不会更好
public function foo()
{
$temp;// or $temp = null;
$temp = $this->getSomeValue();
return $temp ? $temp +1 : null;
}
但是,看到这样的事情并不少见:
public function bar($length = 1)
{
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
此代码依赖于 PHP 足够友好地创建一个数组,并在到达语句$return
时将其分配给它。$return[] = rand();
PHP 会这样做,但是将您的 ini 设置为E_STRICT | E_ALL
会显示它不会这样做而不抱怨它。传递0
给方法时,不会创建数组,PHP 到达return $return;
语句时也会报错:undeclared variable。不仅乱七八糟,还会拖慢你的速度!您最好$return
在范围顶部声明为数组:
public function bar($length = 1)
{
$return = array();//that's it
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
为了安全起见,我还要检查参数类型:
/**
* construct an array with random values
* @param int $length = 1
* @return array
**/
public function bar($length = 1)
{
$length = (int) ((int) $length > 0 ? $length : 1);//make length > 0
$return = array();
for ($i=0;$i<$length;$i++)
{
$return[] = rand($i+1, $length*10);
}
return $return;
}
在大多数情况下(如果不是全部):是的。
如果变量是类属性,则绝对应该在使用前声明它们。
如果变量是函数的局部变量,请在使用之前在该函数中声明它。函数变量仅限于函数的范围(局部变量)。它们不必在使用前声明,但这样做是一种很好的做法,如果你这样做,它会消除警告消息。如果它们没有在其他任何地方使用,它们不应该是属性,
如果您在整个类的上下文中使用它,那么是的,您应该将变量定义为类的成员。
但是,如果您在单个函数的上下文中谈论局部变量,并且该变量不需要在其他地方使用(或不返回),那么不需要。
本质上,在决定是否将其设为类属性之前,您需要确定变量的重要性和范围。
例如:
<?php
class Test {
private $test; // Private property, for use in the class only
public $public_test; // Public Property, for use both internally and external to the class as a whole
public function testing() {
$local = 5; // Local variable, not needed outside of this function ever
$this->test = rand(1, 5);
$calc = $local * $this->test; // Local variable, not needed outside of this function ever
$this->public_test = $calc / 2; // The only thing that the whole class, or public use cares about, is the result of the calculation divided by 2
}
}
对于变量来说,在使用之前定义和初始化它们通常是一个很好的经验法则。这不仅包括定义和初始值,还包括输入值的验证和过滤,以便在对这些变量包含的数据进行具体处理之前建立代码块所基于的所有前提条件。
同样自然地适用于对象成员(属性),因为它们是整个对象的变量。所以它们应该已经在类中定义了(默认情况下它们的值NULL
在 PHP 中)。动态值/过滤可以在构造函数和/或 setter 方法中完成。
可见性规则类似于代码中的任何规则:尽可能少(很难实现的简单规则)。所以保持本地化,然后私有化——取决于它是函数变量还是对象属性。
也许请记住,在 PHP 中,您可以从同一个类中访问私有属性——不仅是同一个对象。知道这一点可能很有用,因为它可以让您将事情保密更长时间。
例如,我有一个计算的(临时)结果。我应该预先声明这个变量吗?
这通常是函数或方法中的局部变量。它是在接收到计算方法的返回值时定义的。所以没有必要预先声明它(本身)。
...
function hasCalculation() {
$temp = $this->calculate();
return (bool) $temp;
}
...
如果计算很昂贵,那么存储(缓存)该值可能是有意义的。当您将其封装时,例如在对象中,这很容易工作。在这种情况下,您将使用私有属性来存储计算后的值。
对这些规则持保留态度,它们是针对一般方向的,您可以从中轻松修改,因此这是可以扩展的,因此是保持灵活性的好方法。