RSS
  • 首页
  • 关于

Author Archive

使用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, 面向对象


原来如此

七月 8, 2010 by admin | 0 Comment »

最近在看石康的《晃晃悠悠》这本书,注意到其中有这么一段:

       运气是一回事,时间是另一回事。  
   这一段我是有时间没运气,华杨不这么看,他说我们是在混时间等运气,果真不幸被他等到了运气。快到新年时,他和刘欣到一家唱片公司去嗅一个小蜜,正碰到一帮人在那里唱歌聊天,华杨对着他想嗅的那个姑娘唱出了“我一眼看见了你的那个部位”,然后进一步发挥,唱什么“谁把你的长裙撩起,谁为你脱下内衣”,后来此歌的旋律被唱片公司的一个制作人所赏识,填了一段少男少女喜欢听的新词,华杨出了一盘磁带,一举成名,到了93年春节一过,连自由市场的小贩都会唱他那首歌了。
   那首歌是刘欣写的,刘欣和华杨从此傍在一起,专心出名挣钱,远离混混世界,忙得不可开交。

恍然大悟,原来感动万千少男少女的《同桌的你》就是这么写出来的。


杂谈 | Tags: 同桌的你, 晃晃悠悠, 石康


使用htaccess来增强Wordpress安全性

七月 6, 2010 by admin | 0 Comment »

这是一篇原创译文,转载请注明出处,原文请单击这里查看。

本文将讨论一些有关于增强Wordpress博客安全性的安全技术,这些技术在那些托管的环境下尤为有效。 

首先我要说明的是本向导并不适合所有人,并且有可能影响一些第三方插件或者模板。 

情况还没有想象中的糟糕,如果你能够应用本向导中的知识,你就可以显著地增强你的博客的安全性。包括暴力攻击、插件枚举、目录列表、敏感信息泄露以及文件包含漏洞等类型的攻击都能被阻止。 

重要说明:请确保在操作之前备份好了您的Wordpress文件和数据库。 

步骤1 – 限制wp-content 和wp-includes

使用 .htaccess 中的 <file> 指令,我们可以限制访问除图像、样式表以及JavaScript之外的文件。这里的 .htaccess 文件看起来如下:

Order Allow,Deny
Deny from all
<Files ~ “\.(css|jpe?g|png|gif|js)$”>
 Allow from all
</Files>

如果你想要允许特定的插件如Democracy被访问,我们可以将下面的指令追加到 wp-content/.htaccess 文件末尾:

<Files “democracy.php”>
 Allow from all
</Files>

将以上内容保存到您的 wp-content 和 wp-includes 目录下的 .htaccess 文件中。补充说明一下,您还可以允许指定的某文件被访问,这样能使您的插件和/或模板正常工作,如果需要的话。这是一个更简洁的办法。

步骤2 – 限制访问 wp-admin

要限制访问 wp-admin,您有两种选择。选择以下方法中的一种,把包含相应指令的 .htaccess 文件放到您的 wp-admin 目录下。

您可以限制 IP:

order deny,allow
allow from a.b.c.d # 这里的a.b.c.d就是您的静态 IP
deny from all

以上代码将阻止那些IP地址不是 a.b.c.d 的访客通过浏览器访问此目录中的任何文件。这里的“a.b.c.d”应当与您的静态IP地址一致。

或者您还可以通过密码来限制:

AuthUserFile /etc/httpd/htpasswd
AuthType Basic
AuthName “restricted”
Order Deny,Allow
Deny from all
Require valid-user
Satisfy any

这里有一个bug。以上的规则代码会引发一个问题,如果那些在您的博客上发表评论的人没有输入邮箱地址,那么就会弹出一个输入密码的输入框。这是因为某些样式表和图片文件也位于wp-admin 目录之中。为了解决这一问题,我们可以将以上的代码包含于文件指令中,这个文件指令只会阻止 .php 文件被访问,不会阻止其它文件。这仍然能够阻止许多直接的攻击,并且同时还提供了许多额外的特性。下面是一个改进版:

<Files ~ “\.(php)$”>
AuthUserFile /etc/httpd/htpasswd
AuthType Basic
AuthName “restricted”
Order Deny,Allow
Deny from all
Require valid-user
Satisfy any
</Files>

就是这样,有了这些措施,您的博客将更加安全。


Web, 译文 | Tags: htaccess, Wordpress, 安全性


归来

七月 5, 2010 by admin | 0 Comment »

之前由于某种不可抗力因素,中国大陆的访客(包括我自己)无法访问wall外的本站,我无可奈何,通过代理工具,将数据备份以后,我选择了另一处虚拟主机,本站才得以恢复,但是有些数据莫名其妙地丢失。好不容易积累起来的一点点访客和PR值,估计也都杯具了。我从来不在博客上谈论political issues,但还是出了这种事,估计是共用此IP的某位朋友做了些不河蟹的内容,导致出现问题,这不是我所能决定的因素,还是那句话,我无可奈何。

但无论如何,“IT狂人的博客”还是回来了。我所喜欢的连续剧《The IT Crowd》第四季也于上月底回归了。这是好事情。


杂谈


因4740G而想起的事

五月 5, 2010 by admin | 0 Comment »

五一买了Acer Aspire 4740G 332g32mn,因为这款笔记本没有预装系统,所以需要刷新一下BIOS,加入SLIC 2.1的信息以便安装Windows 7。在BIOS之家可以找到修改好的ROM文件以及刷新程序,运行程序后,有一个对话框弹出,类似这样:

需要确认操作,然而此时你会发现触摸板和键盘都“失灵”了。原因是在Windows下使用InsydeFlash刷新BIOS时,InsydeFlash程序会将键盘以及触摸板禁用,因此这时候插上USB鼠标即可用鼠标完成刷新。
这一点很重要,我刚开始时就以为是电脑死机了,后来到网上查资料才知道原因。在此做一下笔记,希望看到这篇文章的人不会再走弯路。


未分类 | Tags: BIOS, InsydeFlash, SLIC


选择Web开发框架时需要考虑的15个重要因素

四月 6, 2010 by admin | 0 Comment »
原创译文,未经许可不得转载。
原文地址:http://net.tutsplus.com/tutorials/other/15-most-important-considerations-when-choosing-a-web-development-framework/

    新的Web开发框架正在以一种人们无法企及的速度涌现出来。在本文中,我们将会讨论你的下一个热门Web应用程序应该使用什么样的框架。
    在如今这个时代,抢在您的竞争对手之前发布一个已完成的优雅的应用程序是至关重要的。从头开始编写代码(琐碎事情除外)是一件很费时的事,开发者要花很多时间去重新发明轮子,而这些时间如果用于开发新功能或完善代码会更好。
    这就是Web开发框架存在的理由。它们往往已经包含了应用程序中所有的通用模块,包括数据库存取、权限控制、会话管理以及其它更多功能。
    今天,我们将会讨论的是,你在选择一个框架之前所需要关心的各方面因素。有兴趣吗?那就马上开始。

1. 使用环境


    在你开始考察一个框架之前,你需要列出你的需求,看看这框架能否满足它们。
    如果符合下面这些情形,你需要使用框架:
        你的应用程序主要基于CRUD操作;
        你需要将UI与底层逻辑合理地分开,但你没有时间去实现一个合适的系统;
        你发现你为自己的Web应用程序所编写的程序库覆盖了用户授权、会话以及其它相关的常用功能;
        你的老板希望你能在两天内为他开发一个CMS,而且你已经对框架有所了解;

如果符合下面这些情形,你就不需要框架:
    你需要一个单独的漂亮的URL系统;
    你只需要框架的某一特定部分,如ORM;
    你的时间很紧,而且你必须从头开始学习框架;
    有人告诉你框架能治疗癌症;

2. 许可证

    在你开始使用框架进行开发之前,你得看一下这个框架是基于什么许可证发布的。尽管大部分许可证对于商业应用开发来说是自由的,但仍有一部分不那么自由。你最不希望看到的情况就是,你做完了整个应用程序后才发现,框架的许可证不允许你以商业形式发布代码。事先做好研究功课总好过事后的痛苦。
    切记这不仅仅限制框架本身。你用于额外功能的插件或者扩展项都可能有一个隐藏的使用条款,所以你还得检查一下它的许可证才行。

3. 软件模式

    几乎所有的框架都无一例外地使用了MVC模式。MVC代表的是Model(模型)-View(视图)-Controller(控制器),帮助你保存数据:模型,业务逻辑——控制器以及用户界面——视图,都是各自分开的。这些允许你编写更好更完善的代码,最终完成更好的应用程序。大家都用MVC并不代表你只需要知道这么多。还有其他不同的变种,包括MVP:Model(模型)-View(视图)-Presenter(呈现器), MVA: Model(模型)-View(视图)-Adapter(适配器) 以及 AVC: Application(应用程序)-View(视图)-Controller(控制器)。

4. 主机需求


    作为Web开发者,我们可能更倾向于使用最尖端最顶级的平台,但是我们往往先要考虑到客户的需求以及预算的限制。使用独享主机来发布我们的应用程序往往会导致超出预算,因此我们不得不使用那些拥有正常模块和配置的共享主机。
能很好兼容共享主机的框架包括:
CodeIgniter
CakePHP
Kohana
Zend Framework
大多数其它 PHP框架

安装起来相对复杂的框架包括:

Ruby on Rails
Django
Pylons
大多数非PHP框架

    事实上,你还是能够在共享主机上运行类似于Django的框架,前提是服务器上已经安装了必需的模块。你也可以在CGI模式下运行它,但速度会比原生模式慢很多。

5. 安装容易程度

    选择框架时,安装容易程度也是很重要的因素。一个框架,无论是重量级还是轻量级,如果使用者需要经过一系列繁琐步骤才能安装并且运行它,这就是问题了。
    当应用程序已准备就绪并且测试完成,需要发布到生产服务器上的时候,这也会导致一个大问题。在这种情况下,一个安装和部署都很简单的框架就很有意义。
    对大多数框架而言,安装过程和设置配置文件中的正确参数一样简单,然而对其它框架来说就是一件费时费力的事情。选择一个能让你尽快上手运行的框架。

6. 学习曲线

    每个框架都有它自己的小宇宙:命名规范、目录结构以及诸如此类的东西。某些框架在这方面非常灵活,而其它的就非常严格,例如在出现极小的错误时要抛出错误都非常繁琐。
    某些框架在实现一个功能的时候会遵循一个规范,而其它的就各行其是。
    在选择框架的时候,记住要选择学习曲线最平缓的那个。如果你不知道这框架是用什么语言编写的,那就必须把学习这语言本身的学习曲线也考虑在内。我曾见过不少从CakePHP转向Django的开发者,他们不得不同时学习Python和Django,因此他们纷纷表示压力很大。
    如果你需要同时学习框架和它所使用的语言,你就得悠着点了。

7. 代码库

让我们面对这样一个现实,那就是,人们接受一个框架是因为它的核心库。库必须能让你从编写重复代码的过程中解脱出来,同时也能允许你自行增加更多的功能和特性。
大多数框架提供了以下大部分功能的类库:
AJAX
身份验证
授权
缓存
数据清理
数据验证
模板
URL 映射和重写

    当然,并不是人人都需要一个包罗万象的框架。很多人更希望框架能处理小部分功能而让开发者来处理剩下的那部分。在这些情况下,你需要确保你所考虑的框架是否只拥有你所需要的特性。
    目前框架中流行的趋势是以类库的形式创建框架。换句话说,它允许你根据需要来对库进行替换。在这方面的绝佳典范就是Pylons。它甚至允许你替换它的大多数部分,从ORM到模板语言都行。相对于那些紧耦合的框架,人们喜欢这种松耦合的框架。

8. 数据库抽象以及ORM

    几乎所有应用程序都要存取数据库。如论如何,你都要在开发整个应用程序的过程中这么做,大多数框架都提供了数据库存取类给你使用。因此,当你在选择应用程序的时候,选择能使你的应用程序变得与数据库无关的那一个。万一你要切换数据库,而如果你的框架为你做了这些工作的话,你永远都不用在数据库那部分操心。
    你所要考虑的第二部分就是框架的ORM功能。不需太多技巧,ORM或者Object Relational Mapping(对象关系映射)允许你将数据以对象的形式表现出来,并且将它与其它对象关联起来。如果你想的话,想象一下一个能够获取信息的对象数据库。
包含了ORM特性的框架包括:CakePHP、Django以及Ruby。使用类似Pylons的框架的时候你甚至可以用你自己选择的ORM。

9. 内置的JS库

    争论的另一点就是捆绑的JavaScript库。大多数允许你轻松地切换,然而框架内置的AJAX方法大多数情况下仍然只针对某一特定的JS库。这种潜规则意味着你将不得不手动去开发那一功能。
    另一方面,提供了通用方法的那些框架对你来说的好处是,你可以轻而易举地切换你要使用的JavaScript库。
仅供参考:CakePHP和Ruby on Rails能够以标准形式在Prototype和Scriptaculous之间切换。

10. 单元测试

    我就是那种极其依赖于单元测试的开发者。维基百科上对单元测试的定义是这样的:
单元测试是一种软件检验测试方法,程序员可以通过它来测试源代码中的单个部分是否符合要求。一个单元就是应用程序中最小的可测试的部分。
    在这种情况下,能让我编写单元测试的框架对我很有益处。很多框架,如CodeIgniter、CakePHP还有Zend都允许你创建自定义的测试,作为对核心测试的补充,目的是对应用程序的重要部分进行检查。

11. 可伸缩性

    一般的Web开发者不必考虑框架的可伸缩性问题。通常情况下I/O和网络延迟比框架的可伸缩性更为重要。甚至Twitter那神话般的可伸缩性问题都不是所考虑的框架本身的过错。如果有人要求你放弃一个框架并指出它的伸缩问题,你可以笑而不语。伸缩问题的原因很少由框架产生。当然你也可以对代码稍作优化,但是通常情况下伸缩问题的主要原因在别的方面。

12. 文档


    框架的文档往往是它能否成功的关键。解释详尽的文档能够吸引更多用户和爱好者。质量差的、令人费解的文档会使人们感到迷惑并且惹恼他们,使他们放弃该框架。
    寻找一个文档中包含有丰富的范例、实例代码、文章以及教程的框架。

13. 社区

    尽管有合适的文档,但你不可避免地还是会遇到需要解决的问题,因此你需要去框架的支持社区寻求帮助。我个人已经在很多个社区进行过交流,其中一个社区的成员尖酸刻薄地对新手进行嘲笑,然而另一个社区的成员们却十分热心地为新手提供力所能及的帮助。因此对于最终选择的是哪个框架开始工作的这一问题,我就不做解释了。
    如果一直如此,支持社区将会成就或者毁掉一个框架。社区成员表现得这样急功近利的话,你将会对框架心生怨恨,而不是那些人。社区成员表现得彬彬有礼的话,你就会更倾向于选择那个框架。如果框架拥有友好的社区,能够为新开发者提供帮助的话,那就选择它。

14. Bug 修复/更新

    Web开发者们不愿意自己编写框架的原因之一是他们将要独自完成bug的修复以及更新工作。而对于一个大的框架,每天都有成千上万的开发者对代码进行审视。一旦发现有bug,就能立即得到修复。
    选择一个不那么死气沉沉的框架。你不希望有黑客来告诉你框架有个安全漏洞可以被用来入侵你的网站吧。相对而言,你更希望由框架的开发者们给你提供一个补丁来修正问题。 选择一个更新频繁的框架,更重要的是该框架是开放性的,大家都能发现bugs和尽快修复它们。

15. 创建扩展的容易程度以及可用性

    尽管框架覆盖了一个应用程序的重要基础部分,但是你还需要编写一些代码。尽量使它变得通用,这样你就可以在你的其它应用程序中对它进行重用,甚至是公开发布给人们使用。
    选择一个能够让你轻松进行扩展的框架。以CakePHP为例,扩展一个控制器需要顾及到各个组件以及由辅助函数和视图。无论是那种情况,创建一个扩展就像定义一个继承于父类的子类一样简单。
    选择框架的时候,记住要考虑到插件的可用性。通常情况下你没有时间从头开始创建一个自定义扩展。拥有一个巨大的扩展库可供选择,这就在很大程度上解决了这一问题。扩展的质量比数量更重要。

结论

    现在我们已经讨论了你在选择框架之前所应该考虑的各个方面,包含从框架是否满足需要到bug修复和更新在内的所有内容。但愿这对你有所帮助,也希望你能觉得有趣。


Web, 译文 | Tags: AJAX, AVC, CakePHP, CodeIgniter, CURD, Django, Framework, Kohana, MVC, MVP, ORM, Ruby, Web, Zend, 框架


为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


ASP .Net学习笔记之验证码实现

三月 24, 2010 by admin | 0 Comment »

最新开始学习ASP .Net,因为之前熟悉的是类C的编程语言,所以熟悉起来倒还没太多难度。下面要讲的是Web开发中经常要用到的验证码,先说一说如何用C#来实现它。
我们通常说的验证码,也可以称为CAPTCHA,也就是全自动区分计算机和人类的测试(CAPTCHA, Completely Automated Public Test to tell Computers and Humans Apart),是一种区分用户是计算机和人的公共全自动程序。在CAPTCHA测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。CAPTCHA目前广泛用于网站的留言板,许多留言板为防止有人利用计算机程序大量在留言板上张贴广告或其他垃圾信息,因此会放置CAPTCHA要求留言者必需输入图片上所显示的文数字或是算术题才可完成留言。而一些网络上的交易系统(如订票系统、网络银行)也为避免被计算机程序以暴力法大量尝试交易也会有CAPTCHA的机制。

实现思路:
1.随机生成一个固定长度的字符串,里面可以包含数字、字母甚至汉字都可以,存入一个Session变量中;
2.利用C#的图形相关类来绘制图片,显示在网页上;
3.将用户输入的内容与前面的Session变量进行比对;
下面是Captcha.aspx.cs的内容:

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Drawing;
 
namespace WebApplication2
{
    public partial class Captcha : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string verifyCode = GetRandomString(4);
            this.CreateCaptcha(verifyCode);
            Session["verifyCode"] = verifyCode;
        }
 
        ///
        /// 产生一定长度的随机字符串
        ///
        ///
 
        ///
        private string GetRandomString(int length)
        {
            string[] characters = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", 
 
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
            int charactersLength = characters.Length;
            Random rd = new Random();
            string randomString = "";
            int indexNum = 0;
            for (int i = 0; i &lt; length; i++)
            {
                indexNum = rd.Next(0, charactersLength - 1);    //随机产生索引值
                randomString += characters[indexNum];     //根据索引值取出字符数组中的字符
            }
            return randomString;
        }
 
        ///
        /// 生成图片
        ///
        ///
 
        private void CreateCaptcha(string checkCode)
        {
            if (checkCode == null || checkCode.Trim() == String.Empty)
                return;
 
            System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * 13.5)), 22);
            Graphics g = Graphics.FromImage(image);
 
            try
            {
                //生成随机生成器
                Random random = new Random();
 
                //清空图片背景色
                g.Clear(Color.White);
 
                //画图片的背景噪音线
                for (int i = 0; i &lt; 25; i++)
                {
                    int x1 = random.Next(image.Width);
                    int x2 = random.Next(image.Width);
                    int y1 = random.Next(image.Height);
                    int y2 = random.Next(image.Height);
 
                    g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
                }
 
                Font font = new System.Drawing.Font("Arial", 12, (System.Drawing.FontStyle.Bold /*| System.Drawing.FontStyle.Italic 
 
*/));
                System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new 
 
Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
                g.DrawString(checkCode, font, brush, 2, 2);
 
                //画图片的前景噪音点
                for (int i = 0; i &lt; 100; i++)
                {
                    int x = random.Next(image.Width);
                    int y = random.Next(image.Height);
 
                    image.SetPixel(x, y, Color.FromArgb(random.Next()));
                }
 
                //画图片的边框线
                g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
 
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
                Response.ClearContent();
                Response.ContentType = "image/Gif";
                Response.BinaryWrite(ms.ToArray());
            }
            finally
            {
                g.Dispose();
                image.Dispose();
            }
        }
 
    }
}

怎么调用呢?在我们想要显示验证码的地方,通过img标签即可调用:

<img id="CodeImg" src="Captcha.aspx" alt="" />

注意这里的src属性必须填写验证码生成程序所对应的aspx页面地址,可以是相对地址也可以是绝对地址。
如果我们要加以完善,也就是万一遇到验证码显示不清楚的情况下,给用户提供刷新更换验证码的功能,实现起来也很简单:

<a onclick="document.getElementById('CodeImg').src='Captcha.aspx?tmp='+Math.random()" href="#">单击此处刷新验证码</a>

注意:这里的CodeImg对应的是你前面img标签的ID,必须要一致。
加上tmp=’+Math.random()这一参数的作用是避免缓存。

实际效果就是这样:

图1

图1


ASP .Net | Tags: ASP .Net, C#, CAPTCHA, 验证码


在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


Previous Entries

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