RSS
  • 首页
  • 关于

与标签 ‘PHP’ 相关的文章

使用PHP的Glob()函数来遍历文件夹

七月 22, 2010 by admin | 1 Comment »
原创译文,转载请注明出处。原作者为Marcus Schumann,原文请 单击这里 查看。

你还在使用 opendir() 来遍历文件夹吗?那样岂不是会生成很多冗余的代码?幸运的是,PHP的 glob() 是一个更加智能的解决方案。

引言

下面这个范例的作用就是输出文件夹的一些信息,使用的是传统的 opendir() 函数:

$dir = "/etc/php5/";
 
// Open a known directory, and proceed to read its contents
if (is_dir($dir))
{
 
	if ($dh = opendir($dir))
	{
	while (($file = readdir($dh)) !== false)
		{
			echo "filename: $file : filetype: " . filetype($dir . $file) . "\n";
		}
 
		closedir($dh);
 
	}
 
}

那看起来应该有点熟悉。我们可以大幅度地精简以上的代码:

$dir = "/etc/php5/*";
 
// Open a known directory, and proceed to read its contents
foreach(glob($dir) as $file)
{
	echo "filename: $file : filetype: " . filetype($file) . "<br />";
}

是不是简单多了?很想了解这方法是怎么运行的吗?下面我们就来讲解一下。
glob() 一共支持两个参数,第二个参数是可选的。第一个参数就是文件夹的路径,然而比它更为强大。

步骤1. 第一个参数

第一个参数支持表达式。这就意味着你可以使用多个星号(*)来限制搜索特定的文件类型或者同时搜索多个文件夹。假设你有一个网站允许用户上传图片。每个用户在 “userimages” 目录下都有他/她自己单独的目录。在这些目录里面还有两个额外的目录,名叫 “HD” 和 “TN”,分别代表高清(完整大小)的图片和缩略图。想像一下你要遍历所有用户的 “TN” 目录并且打印出文件名。如果你使用 open_dir() 函数的话,代码量会很大;然而如果使用 glob(),那就简单多了。

	foreach(glob('userImages/*/TN/*') as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

这将会搜索 userImages/any/TN/any 并将返回符合表达式的所有文件的列表。

	Filename: userImages/username1/TN/test.jpg
	Filename: userImages/username1/TN/test3.jpg
	Filename: userImages/username1/TN/test5.png
	Filename: userImages/username2/TN/subfolder
	Filename: userImages/username2/TN/test2.jpg
	Filename: userImages/username2/TN/test4.gif
	Filename: userImages/username3/TN/styles.css

我们还可以进一步在 foreach 语句中限制文件类型:

	foreach(glob('userImages/*/TN/*.jpg') as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

现在,程序将只返回 Jpeg 图片。

	Filename: userImages/username1/TN/test.jpg
	Filename: userImages/username1/TN/test3.jpg
	Filename: userImages/username2/TN/test2.jpg

这就更好了。如果你只需要 Jpeg 和 Gif 文件,不需要其它的,那该怎么办?又或者你只需要打印出目录名称?这就是第二个参数发挥作用的时候了。

步骤2.第二个参数

正如前面所说到的那样,第二个参数是可选的。
但它确实提供了一系列很棒的选项标志。这些选项允许你更改 glob() 的运作方式。
GLOB_MARK: 给返回的每个目录添加斜杠
GLOB_NOSORT: 按照目录中的形式返回文件(不排序)
GLOB_NOCHECK: 如果没有符合条件的结果,则返回搜索表达式
GLOB_NOESCAPE: 反斜杠不引用元字符
GLOB_BRACE: 扩展 {a,b,c} 以匹配 ‘a’, ‘b’, 或 ‘c’
GLOB_ONLYDIR: 只返回符合表达式的目录
GLOB_ERR: 遇到读取错误(例如不可读的目录)时停止执行,默认情况下是忽略错误的

正如你所看到的那样,步骤1末尾的那个需求可以通过 GLOB_BRACE 来满足:

	foreach(glob('userImages/*/TN/{*.jpg,*.gif}', GLOB_BRACE) as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

程序将返回以下内容:

	Filename: userImages/username1/TN/test.jpg
	Filename: userImages/username1/TN/test3.jpg
	Filename: userImages/username2/TN/test2.jpg
	Filename: userImages/username2/TN/test4.gif

如果我们只想要输出子目录名称,我们可以使用 GLOB_ONLYDIR:

	foreach(glob('userImages/*/TN/*', GLOB_ONLYDIR) as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

程序将输出:

	Filename: userImages/username2/TN/subfolder

结论和额外的范例
这个函数在PHP 4.3之后的版本中出现,但很奇怪的是,人们很少使用它。我也是最近才学会怎么使用它的。现在,我经常使用 glob() 来加载我的框架中的插件:

	foreach(glob('includes/plugins/*.php') as $plugin)
	{
		include_once($plugin);
	}

就是这样,希望您能喜欢这个教程,谢谢。


PHP, 译文 | Tags: glob, opendir, PHP, 遍历


[译]PHP面向对象入门

七月 14, 2010 by admin | 0 Comment »
原创译文,转载请注明出处。原作者为Jason Lengstorf,原文请 单击这里 查看。
对很多PHP程序员来说,面向对象编程是一个令人畏惧的概念,充满着复杂的语法以及其它障碍。正如我在我的《Pro PHP and jQuery》这本书中所详细描述的那样,您将学会面向对象编程(OOP),这是一种将相关动作组织在一起从而创造出更紧凑有效的代码的编程风格。

理解面向对象编程

面向对象编程是一种允许开发者们将相似的多个任务组织到类里面的编程风格。这对于保持代码遵循“不要自我重复”(DRY,Don’t Repeat Yourself)这一准则以及保持易维护性是非常有帮助的。

DRY编程的主要好处是,如果一部分信息发生了变化,通常只需要更新一部分代码。开发者们最大的噩梦之一是维护那些数据被反复地声明的代码,这就意味着对程序的任何修改都将变成类似于”Where’s Waldo?”那样的令人无限沮丧的解谜游戏,因为数据和功能都是重复的。

OOP对于很多程序员来说是有点令人畏惧的,因为它引入了新的语法,而且乍一看去,比简单的面向过程或者内联的代码更为复杂。然而,仔细审视一番后你会发现,OOP是一种非常简洁并且极为简单的编程方法。

理解对象和类

在深入了解OOP的细节之前,必须对类和对象之前的区别有一个大概的理解。本章节将讲解的是构建类的基础、它们的不同能力以及它们的一些用途。

你马上就会觉得OOP有点让你犯糊涂:经验丰富的开发者们在谈论对象和类,听起来似乎这二者是可以互换的。然而事实并非如此。二者的巨大区别可能会让你伤透脑筋。

例如,类,就像是房屋的设计图。它在纸上定义好了房屋的形状,各个部分之间的关系构造也都明确地设计好了,尽管这房屋事实上并不存在。

对象,就像是一栋真正的房屋,是根据设计图建造出来的。对象中存储的数据就像是建造房屋的木材、电线以及混凝土。

如果没有依照设计图组织起来,它们就只是一堆东西而已。但是当它们被组织到一起的时候,就成了一栋结构化的有用的房屋。

类,产生数据结构和相关操作,并使用这些信息来构建对象。同一时间内,同一个类可以被用来构建多个独立的对象。继续用我们刚才的那种建筑比喻,从一份设计图可以建造不同的房屋:它们外表看起来一样,但住在里面的人不同,里面的装修和家具也不同。

类结构

创建类的语法是很简洁的:使用class关键字来声明一个类,然后给出类的名称,以及一对花括号({}):

<?php
class MyClass
{
    // Class properties and methods go here
}
?>

创建类以后,使用new关键字,这个新的类就可以被实例化并存储到变量之中:

$obj = new MyClass;

要显示这个类的内容,使用var_dump()函数:

var_dump($obj);

您可以试着将以上代码写到一个新的文件,命名为test.php,保存到您的本地测试文件夹中:

<?php
 
class MyClass
{
	// Class properties and methods go here
}
 
$obj = new MyClass;
 
var_dump($obj);
 
?>

在您的浏览器中打开这个页面,地址是http://localhost/test.php,将会显示以下内容:

object(MyClass)#1 (0) { }

以这种最简单形式,您完成了您的第一个面向对象脚本。

定义类的属性

为了给类添加数据,通常要使用属性或者类特定变量。它们就像常规的变量一样工作,区别就在于,它们被绑定到对象,因此就只能通过对象来访问。
为了给MyClass添加属性,请添加以下代码:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
}
 
$obj = new MyClass;
 
var_dump($obj);
 
?>

这里的public关键字决定了这项属性的可见性,这在接下来的段落中会讲到。然后,使用标准的变量语法来命名这项属性,并且给变量赋值(尽管类的属性是不需要初始值的)。
要读取这项属性并输出到浏览器,您要引用相应的对象才能读取这一属性的值:

echo $obj->prop1;

因为同一个类可能会生成多个实例,如果不引用单独的实例,程序将无法决定要读取哪一个对象的属性。箭头(->)是一种OOP结构,作用是访问给出的对象中所包含的属性和方法。
参照下列代码来修改 test.php 即可读取出这项属性值,而不需要将整个类都读取出来:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
}
 
$obj = new MyClass;
 
echo $obj->prop1; // Output the property
 
?>

刷新您的浏览器,将显示以下内容:

I'm a class property!

定义类的方法

方法是指类特定的函数。类所能实现的单个操作是通过方法的形式在类中定义的。
例如,要创建能够设置和修改类属性$prop1的方法,可以添加如下代码:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
$obj = new MyClass;
 
echo $obj->prop1;
 
?>

注意——OOP允许对象通过$this来引用它们自己。在方法内部也同样是使用$this,但是在类的外部,您必须使用对象的名称。
就像普通函数一样去调用这些方法,但是首先必须先引用它们所属的对象。通过以下代码您就可以实现读取MyClass的属性,修改其属性值,再读取出来:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
$obj = new MyClass;
 
echo $obj->getProperty(); // Get the property value
 
$obj->setProperty("I'm a new property value!"); // Set a new one
 
echo $obj->getProperty(); // Read it out again to show the change
 
?>

刷新您的浏览器,您将看到以下输出结果:

I'm a class property!
I'm a new property value!

“当您使用一个类的多个实例时,OOP的好处就变得显而易见。”

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
// Create two objects
$obj = new MyClass;
$obj2 = new MyClass;
 
// Get the value of $prop1 from both objects
echo $obj->getProperty();
echo $obj2->getProperty();
 
// Set new values for both objects
$obj->setProperty("I'm a new property value!");
$obj2->setProperty("I belong to the second instance!");
 
// Output both objects' $prop1 value
echo $obj->getProperty();
echo $obj2->getProperty();
 
?>

你刷新浏览器后应该就可以看到以下输出结果:

I'm a class property!
I'm a class property!
I'm a new property value!
I belong to the second instance!

正如您所看到的那样,OOP使对象成为单独的实体,这使得分离不同的代码段更加容易。

OOP中的魔术方法

为了更方便地利用对象,PHP也提供了一系列的魔术方法,或者是一些在对象执行特定操作时所调用的特殊方法。这使得开发者们更容易地实现许多实用的任务。

使用构造函数和析构函数

当一个对象被实例化时,通常需要立刻设置好一些东西。为了解决这一问题,PHP提供了魔术方法 __construct(),这个方法在创建新对象的时候会被自动调用。
为了说明构造函数这一概念,我们给MyClass添加一个构造函数,并在创建新实例的时候输出一条消息:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Get the value of $prop1
echo $obj->getProperty();
 
// Output a message at the end of the file
echo "End of file.<br />";
 
?>

注意:__CLASS__ 返回的是所调用的类的名称。这就是人们所熟知的“魔术常量”。有很多魔术常量可供使用,您可以在PHP的手册中找到它们的资料。
刷新浏览器您将看到以下输出结果:

The class "MyClass" was initiated!
I'm a class property!
End of file.

要在对象被销毁的时候调用一个函数,您可以使用 __destruct() 这个魔术方法。这对于类的清空(例如关闭数据库连接)是非常有用的。

在MyClass中定义魔术方法 __destruct() ,当对象被销毁时输出一条消息:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Get the value of $prop1
echo $obj->getProperty();
 
// Output a message at the end of the file
echo "End of file.<br />";
 
?>

定义了析构函数之后,程序将输出以下内容:

The class "MyClass" was initiated!
I'm a class property!
End of file.
The class "MyClass" was destroyed.

“当运行到文件末尾处的时候,PHP会自动释放所有资源。”

要显式地触发析构函数,您可以使用 unset() 函数来销毁对象:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Get the value of $prop1
echo $obj->getProperty();
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo "End of file.<br />";
 
?>

现在程序的输出结果应该是这样的:

The class "MyClass" was initiated!
I'm a class property!
The class "MyClass" was destroyed.
End of file.

转换为字符串

为了避免程序将MyClass当作字符串来输出而产生错误,另一个魔术方法 __toString() 就派上用场了。
如果没有 __toString(),尝试将对象当作字符串来输出的行为将会导致出现致命错误。以下代码就是尝试用echo来输出对象,而不在适当的地方使用魔术方法:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Output the object as a string
echo $obj;
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo "End of file.<br />";
 
?>

这会产生以下输出:

The class "MyClass" was initiated!
 
 
Catchable fatal error: Object of class MyClass could not be converted to string in  
/Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40

为了避免此项错误,添加一个 __toString() 方法:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Output the object as a string
echo $obj;
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo "End of file.<br />";
 
?>

这样的话,尝试将对象转为字符串的时候将会调用 getProperty() 方法。刷新您的浏览器您将看到以下内容:

The class "MyClass" was initiated!
Using the toString method: I'm a class property!
The class "MyClass" was destroyed.
End of file.

提示:除了本段所用到的几个魔术方法,还有更多的魔术方法可供使用,您可以在PHP手册中找到更多资料。

使用类继承

通过extends 关键字,类可以继承其它类的方法和属性。例如,创建另一个类来继承MyClass并增加一个方法,您可以这么做:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Output the object as a string
echo $newobj->newMethod();
 
// Use a method from the parent class
echo $newobj->getProperty();
 
?>

程序将输出以下内容:

The class "MyClass" was initiated!
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

重载继承的属性和方法

为了在新的类中修改现有的属性或者方法的行为,您只需在新的类中重新定义它们,即可实现重载:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function __construct()
    {
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }
 
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Output the object as a string
echo $newobj->newMethod();
 
// Use a method from the parent class
echo $newobj->getProperty();
 
?>

这样,程序将会输出:

A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

重载时保留原有方法的功能

为了在继承的方法中添加功能的同时完整地保留住原始方法的功能,请使用 parent 关键字以及范围解析操作符(::):

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct(); // Call the parent class's constructor
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }
 
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Output the object as a string
echo $newobj->newMethod();
 
// Use a method from the parent class
echo $newobj->getProperty();
 
?>

这将会输出原始构造函数的内容以及新构造函数的内容:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

设置类的属性和方法的可见性

为了更好地控制对象,方法和属性都被设置了可见性。这样控制了属性和方法能从什么地方被访问。有以下三个可见性关键字:public, protected以及private。此外,一个方法或者属性能够被声明为 static (静态的),这样,即便是类没有被实例化,它们也能被访问。

注意:可见性是PHP5的新特性。要了解关于PHP4的OOP兼容性的相关信息,请阅读PHP手册。

受限的(protected)属性和方法

当一个属性或者方法被声明为protected,它就只能在该类自身或者其派生的子类中被访问。
下面的代码将会把getProperty()方法声明为protected,并尝试从类的外部访问它:

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    protected function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
		echo "A new constructor in " . __CLASS__ . ".<br />";
    }
 
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Attempt to call a protected method
echo $newobj->getProperty();
 
?>

运行这段程序的时候会输出以下内容:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.
 
Fatal error: Call to protected method MyClass::getProperty() from context '' in  
/Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55

现在,在MyOtherClass中定义一个新方法来调用 getProperty():

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    protected function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
		echo "A new constructor in " . __CLASS__ . ".<br />";
    }
 
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
 
    public function callProtected()
    {
        return $this->getProperty();
    }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Call the protected method from within a public method
echo $newobj->callProtected();
 
?>

程序将输出您想要的结果:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

私有的(private)属性和方法

如果一个方法或者属性被声明为private,那就只有定义它的那个类才能访问它。这就意味着,即便是另一个类继承了此类,那个类也不能够访问此类中的私有属性和方法。
为了演示这一特性,以下代码将在MyClass中把getProperty()声明为private,然后尝试从MyOtherClass中调用 callProtected():

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    private function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }
 
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
 
    public function callProtected()
    {
        return $this->getProperty();
    }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Use a method from the parent class
echo $newobj->callProtected();
 
?>

运行这段程序,则会显示报错信息:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.
 
Fatal error: Call to private method MyClass::getProperty() from context 'MyOtherClass' in  
/Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49

静态的(static)属性和方法

如果一个属性或者方法被声明为static,那么不需要实例化这个类,它就能够被访问;你只需通过类的名称以及范围解析操作符以及属性或方法名就能访问它了。
“使用静态属性的好处之一是,它们可以在整个脚本运行期间保存一些值不受影响。”
为了演示这一属性,在MyClass中添加一个名为$count的静态属性以及一个名为plusOne()的静态方法。然后设置一个do…while循环,作用是在$count值小于10的时候输出递增的$count值。

<?php
 
class MyClass
{
    public $prop1 = "I'm a class property!";
 
    public static $count = 0;
 
    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }
 
    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }
 
    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }
 
    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }
 
    private function getProperty()
    {
        return $this->prop1 . "<br />";
    }
 
    public static function plusOne()
    {
        return "The count is " . ++self::$count . ".<br />";
    }
}
 
class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }
 
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
 
    public function callProtected()
    {
        return $this->getProperty();
    }
}
 
do
{
    // Call plusOne without instantiating MyClass
    echo MyClass::plusOne();
} while ( MyClass::$count < 10 );
 
?>

注意:访问静态属性的时候,美元符号($)必须在范围解析操作符(::)的后面。

当你运行这段程序的时候,输出的内容是这样的:

The count is 1.
The count is 2.
The count is 3.
The count is 4.
The count is 5.
The count is 6.
The count is 7.
The count is 8.
The count is 9.
The count is 10.

使用文档块(DocBlocks)来注释

尽管不是官方所设置的OOP的一部分,文档块注释风格是一种被广泛认可的类文档编写方式。它不仅为开发者提供了一个编写代码的标准,还被很多流行的软件开发包(SDK)所采纳,例如Eclipse和NetBeans,而且还被用来生成代码提示。
文档块的使用方式就是增加了星号的块注释:

/**
 * This is a very basic DocBlock
 */

文档块真正的好处在于使用tags(标签),标签使用@符号作为开始,紧跟着的是标签的名字以及标签的值。文档块的标签允许开发者们定义文件的作者、类的授权许可、属性和方法的信息以及其它有用的信息。
常用的标签如下:
@author: 使用此标签来注明当前元素(可以是类、文件、方法或者一段代码)的作者。如果有多个作者,同一个文档块中可以使用多个author标签。作者名字的格式是 John Doe .
@copyright: 此标签注明了当前元素版权的年份以及所有者。格式是 2010 Copyright Holder.
@license: 此标签链接到当前元素的授权许可。格式是 http://www.example.com/path/to/license.txt 授权名称.
@var: 此标签指定了变量或者类属性的类型和描述。格式是 type element description.
@param: 此标签注明了函数或者方法的参数的类型和描述。格式是 type $element_name element description.
@return: 此标签注明了函数或者方法的返回值的类型和描述。格式是 type return element description.

下面是一个使用了文档块注释的类的范例:

<?php
 
/**
 * A simple class
 *
 * This is the long description for this class,
 * which can span as many lines as needed. It is
 * not required, whereas the short description is
 * necessary.
 *
 * It can also span multiple paragraphs if the
 * description merits that much verbiage.
 *
 * @author Jason Lengstorf <jason.lengstorf@ennuidesign.com>
 * @copyright 2010 Ennui Design
 * @license http://www.php.net/license/3_01.txt PHP License 3.01
 */
class SimpleClass
{
    /**
     * A public variable
     *
     * @var string stores data for the class
     */
    public $foo;
 
    /**
     * Sets $foo to a new value upon class instantiation
     *
     * @param string $val a value required for the class
     * @return void
     */
    public function __construct($val)
    {
        $this->foo = $val;
    }
 
    /**
     * Multiplies two integers
     *
     * Accepts a pair of integers and returns the
     * product of the two.
     *
     * @param int $bat a number to be multiplied
     * @param int $baz a number to be multiplied
     * @return int the product of the two parameters
     */
    public function bar($bat, $baz)
    {
        return $bat * $baz;
    }
}
 
?>

一旦你仔细审视前面的这个类,你就会发现文档块的好处是显而易见的:一切都被清楚地定义,因此下一个开发者可以很快接手,而不需要费脑筋去思考太多。

比较面向对象和面向过程的代码

事实上并没有一种真正正确或者错误的编程方法。
话虽如此,本段落对软件开发(尤其是大型应用程序开发)中采用面向对象编程方法进行了有力的论证。

理由1:易于实现

尽管起初有点令人畏惧,但事实上OOP提供了一种更容易处理数据的方法。因为对象可以在其内部存储数据,变量就不需要反复地从函数传递到函数了。
而且,同一个类的多个实例可以同时存在,处理大量数据变得轻而易举。例如,想像一下,有两个人的信息需要在一个文件中处理。他们有名字、职业以及年龄。
面向过程的方法
下面是面向过程的处理方法:

<?php
 
function changeJob($person, $newjob)
{
    $person['job'] = $newjob; // Change the person's job
    return $person;
}
 
function happyBirthday($person)
{
    ++$person['age']; // Add 1 to the person's age
    return $person;
}
 
$person1 = array(
    'name' => 'Tom',
    'job' => 'Button-Pusher',
    'age' => 34
);
 
$person2 = array(
    'name' => 'John',
    'job' => 'Lever-Puller',
    'age' => 41
);
 
// Output the starting values for the people
echo "<pre>Person 1: ", print_r($person1, TRUE), "<\/pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "<\/pre>";
 
// Tom got a promotion and had a birthday
$person1 = changeJob($person1, 'Box-Mover');
$person1 = happyBirthday($person1);
 
// John just had a birthday
$person2 = happyBirthday($person2);
 
// Output the new values for the people
echo "<pre>Person 1: ", print_r($person1, TRUE), "<\/pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "<\/pre>";
 
?>

执行后,程序输出下列内容:

Person 1: Array   
(   
    [name] => Tom   
    [job] => Button-Pusher   
    [age] => 34   
)   
Person 2: Array   
(   
    [name] => John   
    [job] => Lever-Puller   
    [age] => 41   
)   
Person 1: Array   
(   
    [name] => Tom   
    [job] => Box-Mover   
    [age] => 35   
)   
Person 2: Array   
(   
    [name] => John   
    [job] => Lever-Puller   
    [age] => 42   
)

尽管这段代码不是很糟糕,但是编码的时候还是要注意很多地方。人物属性数组必须从各个函数之间传递和返回,这就可能导致错误的发生。
为了解决这个范例的问题,留给开发者的东西应当尽可能的少。只有当前操作的那些绝对必要的信息才传递给函数。

下面就轮到OOP来为您解决问题了。

面向对象的方法
下面是针对此范例的面向对象方法:

<?php
 
class Person
{
    private $_name;
    private $_job;
    private $_age;
 
    public function __construct($name, $job, $age)
    {
        $this->_name = $name;
        $this->_job = $job;
        $this->_age = $age;
    }
 
    public function changeJob($newjob)
    {
        $this->_job = $newjob;
    }
 
    public function happyBirthday()
    {
        ++$this->_age;
    }
}
 
// Create two new people
$person1 = new Person("Tom", "Button-Pusher", 34);
$person2 = new Person("John", "Lever Puller", 41);
 
// Output their starting point
echo "<pre>Person 1: ", print_r($person1, TRUE), "<\/pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "<\/pre>";
 
// Give Tom a promotion and a birthday
$person1->changeJob("Box-Mover");
$person1->happyBirthday();
 
// John just gets a year older
$person2->happyBirthday();
 
// Output the ending values
echo "<pre>Person 1: ", print_r($person1, TRUE), "<\/pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "<\/pre>";
 
?>

这段程序会输出以下内容:

Person 1: Person Object
(
    [_name:private] => Tom
    [_job:private] => Button-Pusher
    [_age:private] => 34
)
 
Person 2: Person Object
(
    [_name:private] => John
    [_job:private] => Lever Puller
    [_age:private] => 41
)
 
Person 1: Person Object
(
    [_name:private] => Tom
    [_job:private] => Box-Mover
    [_age:private] => 35
)
 
Person 2: Person Object
(
    [_name:private] => John
    [_job:private] => Lever Puller
    [_age:private] => 42
)

要使这一方法面向对象,需要更多的步骤,但是一旦类被定义,添加和修改人物就变得轻而易举;人物的信息不需要从方法之间传递,只有那些绝对必不可少的信息才从方法之间传递。
如果规模比较小,这种差别可能不明显,但是如果已经合理地实施了的话,一旦您的应用程序的大小增加,OOP将会显著地减少您的工作量。
提示——并非所有东西都需要面向对象化。一个快速处理应用程序内部的少量数据的函数,并不需要写进类里面。根据您的需要来决定使用面向对象还是面向过程。

理由2:更好的组织

OOP的另一个好处是,代码更容易被打包和分类。每个类通常都被写在单独的文件里面,而如果使用了统一的命名规范,访问这些类就是很简单的事情。
假设您有个应用程序中包含了150个类,这些类通过根目录下的一个控制器文件来动态调用。所有150个类都遵循 class.classname.inc.php 这样的命名规范并保存在 inc 目录下。
这个控制器能够实现PHP的 __autoload() 函数,作用是动态地调用某一时刻所需调用的类,而不是在这个控制器文件中把这150个文件都包含进来备用(或者是使用您自己实现的某种智能的方法来包含文件):

<?php
    function __autoload($class_name)
    {
        include_once 'inc/class.' . $class_name . '.inc.php';
    }
?>

将每个类写到单独的文件中,这同样改善了代码的可移植性和可重用性。

理由3:更容易维护

归功于面向对象的紧凑性,相对于冗长的面向过程的面条代码(spaghetti code),对面向对象的代码的修改将会更容易实现。
如果某个特定的信息数组获得了一个新的属性,面向过程的代码(最坏的情况下)可能需要在每个调用了此数组的函数中加上这一属性。
而面向对象的代码很容易添加新的属性,只要修改那个处理这一属性的方法就可以了。

本章节所说到的很多好处都是OOP与DRY编程实践相结合的产物。创建易于维护的面向过程的代码是绝对有可能的,同样也可能写出很糟糕的面向对象的代码。[Pro PHP and jQuery]这本书将尝试展示一种新的编程方法,目的是将面向对象与良好的编码习惯相结合,编写出更干净的、容易阅读和维护的代码。


PHP, 译文 | Tags: OOP, PHP, 面向对象


为NetBeans添加Git支持

三月 29, 2010 by admin | 0 Comment »

说明:以下操作在NetBeans 6.8下进行,不同版本可能会有细微的差别。

Git logo
什么是Git?
Git 是 Linux 的创始人 Linus Torvalds 为了帮助管理 Linux® 内核开发而开发的一个开放源码的版本控制软件。我们可以自己下载这个软件用来管理自己的软件开发项目。与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。 Git 的速度很快,这对于诸如 Linux kernel 这样的大项目来说自然很重要。 Git 最为出色的是它的合并跟踪(merge tracing)能力。

如何安装Git?
Git最初是为了Linux而生,所以一开始并不能直接在Windows下使用。
但是好在Git的开发者们并没有忘记Windows下的程序员,有个名为msysgit开源项目提供了支持:

http://code.google.com/p/msysgit/

访问以下地址获取msysgit的最新版本:

http://code.google.com/p/msysgit/downloads/list

安装过程很简单,就不做过多叙述了。安装完成后我们会发现系统右键菜单会增加几个与Git有关的项目。
Git主要是命令行工具,通过命令行来进行管理,当然也有Windows下的GUI工具如TortoiseGit,但这些都不是本文要叙述的重点。

集成到NetBeans当中
下面叙述一下如何在NetBeans中集成Git支持。
众所周知NetBeans是一个非常优秀而且是开源的IDE,支持Java/PHP/Ruby等多种主流语言的开发,我主要用来开发PHP项目。默认情况下NetBeans已经内置了Kenai、CVS、Subversion、Mecurial等团队开发工具的支持,现在我们要为他添加Git的支持。
开源项目NbGit是一款NetBeans插件,提供了Git支持,因此首先必须得到NbGit的最新版本:

http://code.google.com/p/nbgit/downloads/list

选择下载扩展名为.nbm的插件即可。然后打开NetBeans,依次选择“工具”->“插件”->“已下载”->“添加插件”,然后选中我们刚刚下载到的nbgit-0.3.nbm文件,然后安装即可。
图1 安装NbGit
需要说明的是安装过程中会有一个未签名的警告,不用管它,单击“继续”来安装它。稍等片刻即可安装完成。
图2 警告
此时再打开NetBeans的“团队开发”菜单,我们会发现多了Git这个选项,这就说明已经安装成功。
图3 菜单

如何使用
我们打开“团队开发”->“Git”->“Clone Other”即可克隆一份repository。同样,项目的右键菜单中也有相应的命令可供使用。
图4 Git菜单命令


PHP | Tags: Git, NetBeans, PHP


在Windows下编译适用于PHP 5.2.12及5.2.13的eAccelerator.dll(附下载)

二月 26, 2010 by admin | 11 Comments »

最近PHP 5.2.12及5.2.13发布了,修复了多个bug,因此升级到这一版本是非常必要的。

首先说明一下我的一些参数:
操作系统: Windows 7 Ultimate
Web Server:Apache 2.2.14
Visual Studio: 6.0 (别嫌弃它版本老,即便是在Win7下它还是能用的,当然你用Visual Studio 2008也行)

什么是eAccelerator?
eaccelerator是一个自由开放源码php加速器,优化和动态内容缓存,提高了性能php脚本的缓存性能,使得PHP脚本在编译的状态下,对服务器的开销几乎完全消除。 它还有对脚本起优化作用,以加快其执行效率。

1.首先下载编译好的PHP二进制包。(稍后会用到) 地址如下:
http://cn.php.net/distributions/php-5.2.12-Win32.zip

http://cn.php.net/distributions/php-5.2.13-Win32.zip

2.再下载PHP的源代码,稍后编译eAccelerator的时候会用到。地址如下:
http://cn2.php.net/get/php-5.2.12.tar.bz2/from/a/mirror

http://cn2.php.net/get/php-5.2.13.tar.bz2/from/a/mirror

3.升级PHP:
这一过程很简单,首先关闭Apache,然后将压缩包里解压出来的所有文件替换掉原来的文件即可。例如你原来的PHP程序文件位于 D:\php,那么请将php-5.2.13-Win32.zip(或者php-5.2.12-Win32.zip)解压到这一路径下覆盖原有文件。

4.启动Apache,我们会收到一条报错信息,Apache无法启动。打开Apache的日志文件(此文件路径为apache\logs\error.log),我们会看到这样的提示信息:

PHP Warning:  [eAccelerator] This build of "eAccelerator" was compiled for PHP version 5.2.11.
Rebuild it for your PHP version (5.2.13) or download precompiled binaries.

意思就是当前的eAccelerator是为PHP 5.2.11编译的,不适用于5.2.13。我们应该重新编译一份eAccelerator。

5.下载一份eAccelerator的源码。地址如下:
http://bart.eaccelerator.net/source/0.9.5.3/eaccelerator-0.9.5.3.zip

6.将第2步骤下载到的PHP源码解压到某一目录下,例如 E:\php。然后打开你的PHP程序目录(也就是你的php.exe所在的目录),找到其中dev子目录下的php5ts.lib文件,把它复制到E:\php这一位置。

7.打开E:\php\ext,在这下面创建一个目录命名为eaccelerator,然后将第5步骤下载到的压缩包解压到此目录下。此时的目录结构应该是这样的:

图1

图1

8.打开win32子目录,其中应该有一个名叫eAccelerator.dsw的项目文件,用VS开发环境打开它(比如我用的就是VS6.0),打开”组件”>”配置”,选中 Win32 Release PHP5 这一选项,单击“关闭”。

图2

图2

9.按下F7键(或选择工具条中的编辑按钮)开始编译,稍等片刻,编译成功,你就可以在win32目录下看到生成了一个Release子目录,打开这个子目录,你就会看到已经生成了eAccelerator.dll文件。
将这个文件复制到你的PHP扩展目录下(如D:\php\ext),替换掉原有的文件,然后启动Apache,你就会发现eAccelerator已经成功加载了。

图3

图3

或者

猛击此处下载编译好的dll文件

Visual Studio 2008下编译可能会出现类似于“不能分配常量大小为 0 的数组”这样的报错信息,解决办法如下:

找到源码目录的main子目录,打开它,找到以下文件:
config.w32.h
 
在这个文件里查找 #define _USE_32BIT_TIME_T 1,将这一行注释掉。再重新编译即可。


PHP | Tags: eaccelerator, PHP, windows


phpMyAdmin升级到3.2.x版遇到的常见问题

九月 30, 2009 by admin | 0 Comment »

phpMyAdmin是一个用PHP编写的基于Web的MySQL管理工具。从事过PHP+MySQL开发的朋友肯定接触过它,非常方便。最近把电脑上的phpMyAdmin升级到了3.2.2版,遇到了一些问题,在此总结一下。

1. “空密码登录被禁止”  问题
很多时候我们在本机测试时会将root用户密码设置为空。但升级到phpMyAdmin 3.2.2版的时候,会遇到无法以空密码登录root用户的情况。怎么解决呢? 请参照如下步骤:
(1) 找到你的phpMyAdmin程序所在的目录,这个根据你个人的情况有所不同。
(2) 打开 phpMyAdmin\libraries\ 路径下的 config.default.php 这个文件,找到下面这行

$cfg['Servers'][$i]['AllowNoPassword'] = false;

将其修改为

$cfg['Servers'][$i]['AllowNoPassword'] = true;

(3) 重新访问你的phpMyAdmin,你会发现空密码的root用户也可以登录了。

2. “配置文件现在需要一个短语密码” 问题
在登录进去之后可能会看到“配置文件现在需要一个短语密码”这条警告信息。这是因为你没有设置一个用来给Cookie加密的密钥。解决方法还是首先打开上文所说的 config.default.php 文件,并找到下面这行

$cfg['blowfish_secret'] = '';

将其修改为

$cfg['blowfish_secret'] = '你的密钥';

说明: 这里的“你的密钥”是你所设置的密钥字符串,可以随意设置。
修改保存之后,重新登录phpMyAdmin就可以了。

3. “无法载入mcrypt扩展” 问题
这个问题与phpMyAdmin没有多少关系,是因为你的 PHP 运行环境没有开启mcrypt扩展。以Windows下为例,首先你要确保PHP目录的ext子目录下有 php_mcrypt.dll 这个文件,没有的话去网上下载一个。然后打开你的 php.ini 文件,找到下面这行

;extension=php_mcrypt.dll

去掉这行行首的分号,保存,然后重启Apache就可以开启mcrypt支持了。这个时候重新登陆phpMyAdmin,此问题就已经解决。


PHP, Web | Tags: MYSQL, PHP, phpMyAdmin


IT狂人的博客

  • 声明

    本博文章及相关作品(包括但不限于文字、图片),除特别说明为转载外,均属本人原创,依据《国家知识产权法》、《著作权法》和《信息网络传播权保护条例》,原创知识产权、版权均为本人所有,本人享有著作权,并受法律保护。

    文章欢迎转载,但请事先与本人联系:email
    未经本人许可,任何人不得转载或使用整体或任何部分的内容。未尽事宜,依据相关法律法规处理。

  • 分类目录

    • ASP .Net (1)
    • CodeIgniter (8)
    • PHP (8)
    • Web (5)
    • 未分类 (1)
    • 杂谈 (4)
    • 译文 (7)
    • 音乐&电影 (1)
  • 文章索引模板

    • 2010年七月 (5)
    • 2010年五月 (1)
    • 2010年四月 (1)
    • 2010年三月 (2)
    • 2010年二月 (1)
    • 2010年一月 (2)
    • 2009年十二月 (1)
    • 2009年十月 (2)
    • 2009年九月 (3)
    • 2009年八月 (10)
  • 标签

    AJAX API AVC CakePHP CHM CodeIgniter CURD Django DroidSansFallback eaccelerator footer Framework Fran Healy Git helper IT Kohana MVC MVP MYSQL NetBeans Oasis ORM pChart pdf PHP phpMyAdmin Ruby tcpdf techified time Travis Twitter Web windows Wordpress XML Zend 传记 外链 大写 孔乙己 框架 盗链 过滤
  •  

    2010年七月
    一 二 三 四 五 六 日
    « 五    
     1234
    567891011
    12131415161718
    19202122232425
    262728293031  
  • Playlist


  • 最近评论

    • cnenc 在 使用PHP的Glob()函数来遍历文件夹 上的评论
    • TCPDF开源项目 - PDF - php开源项目 - php免费pdf生成软件 - php开源软件 - TCPDF - 开源网 在 使用TCPDF输出完美的中文PDF文档 上的评论
    • 匿名 在 在Windows下编译适用于PHP 5.2.12及5.2.13的eAccelerator.dll(附下载) 上的评论
    • 笑话大王 在 使用TCPDF输出完美的中文PDF文档 上的评论
    • admin 在 在Windows下编译适用于PHP 5.2.12及5.2.13的eAccelerator.dll(附下载) 上的评论
  • 链接

    • cnBeta.COM
    • CodeIgniter 中国
    • jQuery中文社区
    • Lily Allen
    • Mtime时光网
    • W3School
    • 小众软件
    • 破烂熊乐园
    • 韩寒
Copyright © 2010 IT狂人的博客 All Rights Reserved. XHTML CSS THEME by I SOFTWARE REVIEWS