Submitted by gouki on 2009, May 8, 3:38 PM
在数据库驱动的 Web 应用程序中实现 PHP5 对象的持久,朝着完全面向对象的 Web 应用程序开发迈进重要的一步。
许多开发人员都认同 PHP5 的面向对象实现的简洁和高效,并且同样被世界上最著名的数据库 — Oracle — 的强大功能和强健性所吸引。然而,从逻辑上更进一步 — 将 PHP 对象存储在数据库中以进行 Web 应用程序开发 — 可能将非常困难。
在这篇方法文档中,您将了解到如何通过一个(在 OracleDatabaseObject 程序包(下载 )中提供的)对象持久层来存储和检索作为 Oracle 数据库中的对象的 PHP5 对象。利用这一技巧,任何 Oracle 开发人员都能够在他们的 Web 应用程序中最终实现完全面向对象 — 从而专注于应用程序逻辑,而不是麻烦的 SQL 和编码。
什么是对象持久层?
在解释如何在 Oracle 数据库中实现 PHP 对象的持久的机制之前,大家需要先了解支持它们的原理:对象持久层的概念。
世界上最受欢迎的脚本语言 PHP 只是在最近才为我们提供了面向对象的一个完整和合理的实现(在 PHP5 中)。这为希望效仿面向对象方法的严格性和灵活性的开发人员展现了一个激动人心的前景,面向对象方法在“传统的”编程环境中已经存在了很多年。然而,由于 关系数据库在 Web 的发展中扮演了如此关键的角色,希望充分利用这种方法的开发人员将面临一个的两难境地:对象技术明显不适合关系数据库技术。数据库需要表,而不是类;表需 要行,而不是对象。教科书上把这种现象称为“阻抗失谐”。
早于对象技术出现的关系数据库可以对作为简单类型集中在一起的简单数据进行适当地建模;例如,Person 表可以包含姓名 (varchar2)、身高 (INT) 和出生日期 (DATE) 列。相比而言,对象技术支持复杂数据类型的概念。例如,Person 对象可以包含 name 和 height 的基本类型,但也可以包含类型为 Person 的 partner、类型为 Job 的 job,每一种类型都有它们自己的复杂的数据结构。
因此,想收获面向对象方法的好处并存储复杂数据类型(PHP 对象)的 Web 开发人员只有两种选择:模拟或使用对象数据库,或者更可能的是,以专门的方式简单地存储数据对象。后一种做法(虽然很流行)是完全不可接受的,因为它抛弃 了面向对象的简洁性、可扩展性和可重用性,而这些是面向对象的主要好处。
幸运的是,Oracle 提供了对象类型、PL/SQL 和 REF。这些特性结合在一起形成了 Oracle 自己的面向对象实现;虽然这种实现从技术上看是不完整的,但它的确使开发人员能够容易地将对象存储为数据库对象,而不是以固定类型存储在表的行中。
然而,只是因为 PHP 和 Oracle “使用”对象技术并不意味着可以将 PHP 对象存储为 Oracle 对象(反之亦然)。因此,需要对象持久层服务来使 PHP 开发人员能够简单、高效地在 Oracle 数据库中存储和检索对象。
可以通过许多方式来执行这一操作,但所有方法都必须满足同样的需求:
必须通过简单、高效的服务来存储和检索对象。
存储在数据库中的对象必须能够包含对其他对象(复杂数据类型)的引用。
每一个对象必须有一个唯一的标识符。
当保存对象时,还必须能够保存所有其他相关的对象状态。
当检索对象时,还必须能够检索所有其他相关的对象状态。
OracleDatabaseObject 程序包是我对这些需求的实现。它反映了现有的最简洁的方法:使用抽象类和数据类型来对通用 的 Oracle 数据库对象建模。该方法允许任意类简单地继承这个通用类,从而继承持久所需的所有服务 — 实质上将其自身封装在一个可以和 Oracle 数据库接口的层中(参见下图)。
对象持久层将动态提供在数据库中实现对象持久所需的一切。无论何时当调用了方法 save() 来将 PHP5 对象存储到数据库中时,持久层的第一个任务是测试在此之前是否存储过这种类型的对象。如果没有,则将检查对象的状态(属性类型和值)。考虑以下对象:
如果在 Person1 上调用了 save() 方法,并且这是要保存在数据库中的第一个类型为 Person 的对象,那么将检查状态和它们的类型 — 在这种情况下,属性 Name、Age 和 Partner 分别有 PHP5 类型 String、Integer 和 Person。然后,要使这个对象能够持久,持久层将创建一个 Oracle 对象类型(也称为 Person),它的结构基于它对应的 PHP5 对象的状态。该层将在 Oracle 中复制 PHP5 类型 — Name (PHP5 string) 将变为 Oracle VARCHAR2;Age (PHP5 integer) 将变为 Oracle Number;PHP5 Partner(类型为 Person)将变为类型为 Person 的 Oracle REF。(关于这些转换的概述,请查看表 1。)
PHP5 类型
Oracle 对象类型
Numeric
Number
String
VARCHAR2
Array
VARCHAR2 *
Object
Object
Associated Object
REF to Object
* 在撰写本文时,出于性能的目的,数组作为序列化的字符串以 VARCHAR2 类型存储在 Oracle 中。
然而,在未来,它们可能由 Oracle VARRAY 来实现。
一旦创建了 Oracle 对象类型结构来模拟它对应的 PHP5 类,属性值就将被保存到新创建的对象类型的表中。按照上述的第 4 点需求,当保存一个对象及其关联的对象时(如以上示例所示),还必须保存所有的关联关系。只需通过确保在检查和保存当前对象的内部状态时调用相关对象的 save() 方法来实现这一需求。
了解这些实现细节对于判断持久层具体在做些什么非常有用,但这种方法的强大之处在于您不需要了解这些。作为开发人员,您需要做的全部是利用交互对象来开发 和实现类 — 完全可以忽略所涉及的编程工作。利用这一层的服务,您可以在数据库中存储和检索对象,而永远无需设置表或处理 SQL,从而使您只需考虑应用程序自身的逻辑。
现在让我们看一个例子。
何时使对象持久
利用类和对象进行开发的实践是现在 PHP5 开发人员的日常工作。但并非所有这些对象都将在 Oracle 数据库中持久。因此,第一步是要决定是否需要为指定类的对象添加持久服务。
随着开发人员倾向于对 Web 全部使用面向对象,我们将共同创建并能够访问成千上万个类 — 但我们必须记住它们并非全部需要持久。相反,您必须考虑您的类代表了什么抽象概念,以及将如何在应用程序中使用类的对象。作为一条通用的基本原则:
如果在脚本完成之后必须存储对象的状态,并且在脚本运行时必须能够访问和/或更新对象的状态,那么就必须持久对象。
例如,大部分面向对象的 Web 开发人员会在应用程序中使用表单对象 — 但很少需要将它们存储在数据库中。例如,您不需要保存表单对象(包括其元素、目标、名称等),因为它在被创建之后就不会改变;所以无需在脚本中设置对象属 性并将它们存储在数据库中。相比而言,如果您在开发一个电子日历应用程序,那么您可能想使用条目对象作为每一天的对象,这种对象将在添加和编辑它们时改 变。当添加或修改了一个条目时,对象的状态也将改变;当一个条目变化时,您将把更新的版本保存在数据库中。
因此让我们利用这种应用程序的示例来浏览一下使用在下载 (在撰写本文时提供了测试版本,计划在 2005 年底之前推出产品版本)中提供的 OracleDatabaseObject 程序包 (OracleDatabaseObject.class.php) 将持久服务添加到一个简单的 TestEntry 类 (TestEntry.class.php) 中的过程。
将 Oracle 数据库持久添加到类中
原始的 TestEntry 类如下所示:
PHP代码
class TestEntry { public $title ; public $body ; public $author ; public $dayName ; function display() { Echo $this ->title . "<BR>" . $this ->body . "<BR>" . $this ->author; } }
传统上将这个类的对象存储在 Oracle 数据库中将非常复杂。这个过程将包含创建一个与类的内部状态类似的表,然后利用关系 SQL 编写一系列的过程函数来插入/更新/删除类的各个属性。这是一个非常复杂、低效的任务 — 当对象变得更复杂时(可能包含数组或其他对象),它将变得几乎不可能完成。
OracleDatabaseObject 类使得您在其他方式下将手动完成的一切 — 例如存储类的内部状态(包括所有属性的类型)和创建 Oracle 对象类型 — 都变为动态完成,从而使得这个过程变得非常简单。最终的结果是您永远无需担心创建或修改 Oracle 数据库中的表或类型;您所需做的一切是专注于应用程序的逻辑。
因此,下面将创建 TestEntry 对象,并在数据库中存储和检索它们,让您的类继承 OracleDatabaseObject 类,该类已经内置了您所需的所有服务(参见表 2)。
表 2
方法
参数
目的
用途示例
对象
save()
无
将当前对象保存为数据库中的对象
$anObject->save()
load()
无
利用当前的 objectName 从数据库中加载对象
$anObject->load()
类
addDatabaseUser ($username )
包含用户名的字符串,该字符串将用于存储类对象的数据库
为存储类的对象的 Oracle 服务器设置用户名、口令和数据库名称,使得能够利用各自的用户名和口令在各个数据库中存储类。
ClassName::setUserName(‘scott’)
addDatabasePass ($password)
包含口令的字符串,该字符串将用于存储类对象的数据库
ClassName::setPassword(‘tiger’)
addDatabaseName ($databasename )
包含数据库名称的字符串,该字符串将用于存储类对象的数据库
ClassName::setDatabase(‘orcl’)
将这些服务提供给 TestEntry 类的过程为:
PHP代码
<?php include_once 'DatabaseObject.class.php' ; include_once 'OracleDatabaseObject.class.php' ; class TestEntry extends OracleDatabaseObject { public $title ; public $body ; public $author ; public $dayName ; function display() { echo $this ->title . "<BR>" . $this ->body . "<BR>" . $this ->author; } } 下面您将通过使用 include_once 关键字(如第 1 行和第 2 行所示)来包含对您所需的类的访问权(OracleDatabaseObject 是一个继承 DatabaseObject 的抽象类)。然后可以使用 PHP5 继承关键字 extends (第 4 行)来继承 OracleDatabaseObject 类。继承的工作方式是获取父类的所有特性(方法)和属性(属性)并将它们提供给子类。这是一个简单但强大的想法(如下图所示):最初的 TestEntry 类继承 OracleDatabaseObject 类,产生一个结合了两者的特性的新的 TestEntry 类。
(左边显示的继承将产生右边显示的 Entry 类的一个新的版本。)
接下来,您将创建 TestEntry 类的对象,并使用服务层在 Oracle 数据库中保存和检索对象。
创建和使用 Oracle 持久对象
现在您的类拥有了所需的服务,将对象保存至数据库的过程将非常简单,如下所示 (ExampleA.php):
PHP代码
<?php include_once "DatabaseObject.class.php" ; include_once "OracleDatabaseObject.class.php" ; include_once "TestEntry.class.php" ; TestEntry::addDatabaseUser('scott' ); TestEntry::addDatabasePass('tiger' ); TestEntry::addDatabaseName('orcl' ); $anEntry = new TestEntry(); $anEntry ->title = 'Meeting with boss - 9am' ; $anEntry ->body = 'Meeting with boss scheduled to discuss raise' ; $anEntry ->author = 'Joe Bloggs' ; $anEntry ->dayName = 'Tuesday' ; $anEntry ->objectName = 'Tuesday' ; $anEntry ->display(); $anEntry ->save();
在继承 OracleDatabaseObject 之后,您必须通过使用表 2 中所示的服务来将用户名、口令和数据库名称与类绑定(如第 5-7 行所示的方式)。这个操作将使得能够通过单独的用户名、口令和数据库名称来获取各个类(从而获取该类的所有对象) — 顺便说一句,这将为您的对象提供非常细粒化的安全性。
不过,您可能希望为对象提供特定的名称,例如 Tuesday 。这种方式将使您能够通过调用 load() 方法从数据库中快速容易地检索对象(如下面的 ExampleB.php 所示)。
您应当注意的最后但可能最重要的一件事是第 14 行中的方法 save()。这个方法也继承了 OracleDatabaseObject 类,它只是将对象保存到数据库中。
加载 Oracle 对象
您已经看到了在 Oracle 中保存对象有多容易。您甚至不需要接触数据库!自然,下一步是检索它 — 这将一样简单。
使用 ExampleB.php 示例,您将把数据库对象加载到一个新的 PHP5 对象中(如下所示):
PHP代码
<?php include_once "DatabaseObject.class.php" ; include_once "OracleDatabaseObject.class.php" ; include_once "TestEntry.class.php" ; TestEntry::addDatabaseUser('scott' ); TestEntry::addDatabasePass('tiger' ); TestEntry::addDatabaseName('orcl' ); $anEntry = new TestEntry(); $anEntry ->objectName = "Tuesday" ; $anEntry ->load(); $anEntry ->display();
这将产生和 ExampleA 相同的输出:只需从存储在数据库中的对象中重新加载对象的状态,无需任何复杂的调用和查询,并且只需通过调用 display() 方法来显示对象的状态。
SQL代码
$sql = "SELECT * FROM: ( SELECT r.*, ROWNUM as row_number FROM: ( $select ) r ) WHERE row_number BETWEEN :start_row AND :end_row" ;
关于更广泛的演示,请查看提供下载 的完整的示例电子日历应用程序。它包含了类的源代码以及 UML 图,从而使您能够更彻底地研究这一技巧。
使用 Oracle/PHP5 对象
将对象存储在数据库中不只是一个小花招;相反,它是满足“完全在面向对象范例中进行开发”的需求的最后一步。它使您能够无缝地使用在传统的大型面向对象编 程中流行的所有技巧 — 使用诸如业务对象、UML 和契约式设计等方法 — 来进行分析、设计、开发和测试。这是一种激进的想法,但 Web 开发领域正朝这个方向努力。
Barry McKay 是一个居住在苏格兰 Glasgow 的兼职 Web 开发人员和面向对象方法的拥护者。他还是 International PHP Magazine 的撰稿人。
PHP | 评论 :0
| 阅读 :16289
Submitted by gouki on 2009, May 7, 11:25 AM
APC其实是PHP5自带的东西,只需要把xxx.dll前的注释去掉就可以用了,不象其他的加速 ,还需要装软件,什么xCache啦,eacceraltor之类的,都需要额外编译好之后放到扩展目录下才行(当然我说的是windows下面的,linux下面就不太一样了)
既然是自带的,又这么好,总要有个介绍的吧?
原文:http://blog.goguoguo.com/html/y2009/311.html
作者:土 豆
先说说php程序的执行流程吧,说明了这个,才好开始我们的优化之旅。
客户端(譬如浏览器)
—》请求Get hello.php
—-》cgi服务器接(譬如apache)收到请求,根据配置寻找php的处理程序(譬如mod_php)
—-》apache加载php的处理程序,php的处理程序读取php.ini初始化php的解释环境
—-》mod_php定位寻找hell.php,将其载入到内存中来
—-》mod_php编译源代码成为opcode树
—-》mod_php执行opcode 树
—-》生成结果给浏览器
在这个过程中我们有哪些地方可以优化呢:
1 将mod_php fast-cgi化,避免每次都要加载这个模块,这个模块还要每次都去初始化php的解释环境
2 缓存php文件的opcode码,这样话,避免每次都去编译。
缓存opcode码有很多软件,apc、以及zend提供的cache等。
转载一个apc的配置和使用:
Alternative PHP Cache(APC)是 PHP 的一个免费公开的优化代码缓存。它用来提供免费,公开并且强健的架构来缓存和优化 PHP 的中间代码。
在 Windows 下,APC 要求有 c:\tmp 目录,并且该目录要对 Web 服务器进程可写。
1. 安装:
以PHP extension 形式安装.
2. 配置
apc.enabled boolean
apc.optimization optimization
选项在脚本中可以改变
APC PHP.ini配置选项详解
[APC]
; Alternative PHP Cache 用于缓存和优化PHP中间代码
apc.cache_by_default = On
;SYS
; 是否默认对所有文件启用缓冲。
; 若设为Off并与以加号开头的apc.filters指令一起用,则文件仅在匹配过滤器时才被缓存。
apc.enable_cli = Off
;SYS
; 是否为CLI版本启用APC功能,仅用于测试和调试目的才打开此指令。
apc.enabled = On
; 是否启用APC,如果APC被静态编译进PHP又想禁用它,这是唯一的办法。
apc.file_update_protection = 2
;SYS
; 当你在一个运行中的服务器上修改文件时,你应当执行原子操作。
; 也就是先写进一个临时文件,然后将该文件重命名(mv)到最终的名字。
; 文本编辑器以及 cp, tar 等程序却并不是这样操作的,从而导致有可能缓冲了残缺的文件。
; 默认值 2 表示在访问文件时如果发现修改时间距离访问时间小于 2 秒则不做缓冲。
; 那个不幸的访问者可能得到残缺的内容,但是这种坏影响却不会通过缓存扩大化。
; 如果你能确保所有的更新操作都是原子操作,那么可以用 0 关闭此特性。
; 如果你的系统由于大量的IO操作导致更新缓慢,你就需要增大此值。
apc.filters =
;SYS
; 一个以逗号分隔的POSIX扩展正则表达式列表。
; 如果源文件名与任意一个模式匹配,则该文件不被缓存。
; 注意,用来匹配的文件名是传递给include/require的文件名,而不是绝对路径。
; 如果正则表达式的第一个字符是”+”则意味着任何匹配表达式的文件会被缓存,
; 如果第一个字符是”-”则任何匹配项都不会被缓存。”-”是默认值,可以省略掉。
apc.ttl = 0
;SYS
; 缓存条目在缓冲区中允许逗留的秒数。0 表示永不超时。建议值为7200~36000。
; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。
apc.user_ttl = 0
;SYS
; 类似于apc.ttl,只是针对每个用户而言,建议值为7200~36000。
; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。
apc.gc_ttl = 3600
;SYS
; 缓存条目在垃圾回收表中能够存在的秒数。
; 此值提供了一个安全措施,即使一个服务器进程在执行缓存的源文件时崩溃,
; 而且该源文件已经被修改,为旧版本分配的内存也不会被回收,直到达到此TTL值为止。
; 设为零将禁用此特性。
apc.include_once_override = Off
;SYS
; 关于该指令目前尚无说明文档,参见:http://pecl.php.net/bugs/bug.php?id=8754
; 请保持为Off,否则可能导致意想不到的结果。
apc.max_file_size = 1M
;SYS
; 禁止大于此尺寸的文件被缓存。
apc.mmap_file_mask =
;SYS
; 如果使用–enable-mmap(默认启用)为APC编译了MMAP支持,
; 这里的值就是传递给mmap模块的mktemp风格的文件掩码(建议值为”/tmp/apc.XXXXXX”)。
; 该掩码用于决定内存映射区域是否要被file-backed或者shared memory backed。
; 对于直接的file-backed内存映射,要设置成”/tmp/apc.XXXXXX”的样子(恰好6个X)。
; 要使用POSIX风格的shm_open/mmap就需要设置成”/apc.shm.XXXXXX”的样子。
; 你还可以设为”/dev/zero”来为匿名映射的内存使用内核的”/dev/zero”接口。
; 不定义此指令则表示强制使用匿名映射。
apc.num_files_hint = 1000
;SYS
; Web服务器上可能被包含或被请求的不同源文件的大致数量(建议值为1024~4096)。
; 如果你不能确定,则设为 0 ;此设定主要用于拥有数千个源文件的站点。
apc.optimization = 0
; 优化级别(建议值为 0 ) 。
; 正整数值表示启用优化器,值越高则使用越激进的优化。
; 更高的值可能有非常有限的速度提升,但目前尚在试验中。
apc.report_autofilter = Off
;SYS
; 是否记录所有由于early/late binding原因而自动未被缓存的脚本。
apc.shm_segments = 1
;SYS
; 为编译器缓冲区分配的共享内存块数量(建议值为1)。
; 如果APC耗尽了共享内存,并且已将apc.shm_size指令设为系统允许的最大值,
; 你可以尝试增大此值。
apc.shm_size = 30
;SYS
; 每个共享内存块的大小(以MB为单位,建议值为128~256)。
; 有些系统(包括大多数BSD变种)默认的共享内存块大小非常少。
apc.slam_defense = 0
;SYS(反对使用该指令,建议该用apc.write_lock指令)
; 在非常繁忙的服务器上,无论是启动服务还是修改文件,
; 都可能由于多个进程企图同时缓存一个文件而导致竞争条件。
; 这个指令用于设置进程在处理未被缓存的文件时跳过缓存步骤的百分率。
; 比如设为75表示在遇到未被缓存的文件时有75%的概率不进行缓存,从而减少碰撞几率。
; 鼓励设为 0 来禁用这个特性。
apc.stat = On
;SYS
; 是否启用脚本更新检查。
; 改变这个指令值要非常小心。
; 默认值 On 表示APC在每次请求脚本时都检查脚本是否被更新,
; 如果被更新则自动重新编译和缓存编译后的内容。但这样做对性能有不利影响。
; 如果设为 Off 则表示不进行检查,从而使性能得到大幅提高。
; 但是为了使更新的内容生效,你必须重启Web服务器。
; 这个指令对于include/require的文件同样有效。但是需要注意的是,
; 如果你使用的是相对路径,APC就必须在每一次include/require时都进行检查以定位文件。
; 而使用绝对路径则可以跳过检查,所以鼓励你使用绝对路径进行include/require操作。
apc.user_entries_hint = 100
;SYS
; 类似于num_files_hint指令,只是针对每个不同用户而言。
; 如果你不能确定,则设为 0 。
apc.write_lock = On
;SYS
; 是否启用写入锁。
; 在非常繁忙的服务器上,无论是启动服务还是修改文件,
; 都可能由于多个进程企图同时缓存一个文件而导致竞争条件。
; 启用该指令可以避免竞争条件的出现。
apc.rfc1867 = Off
;SYS
; 打开该指令后,对于每个恰好在file字段之前含有APC_UPLOAD_PROGRESS字段的上传文件,
; APC都将自动创建一个upload_的用户缓存条目(就是APC_UPLOAD_PROGRESS字段值)。
3. 函数:
apc_cache_info - Retrieves cached information (and meta-data) from APC’s data store
apc_clear_cache - Clears the APC cache
apc_define_constants - Defines a set of constants for later retrieval and mass-definition
apc_delete - Removes a stored variable from the cache
apc_fetch - Fetch a stored variable from the cache
apc_load_constants - Loads a set of constants from the cache
apc_sma_info - Retrieves APC’s Shared Memory Allocation information
apc_store - Cache a variable in the data store
apc的用法比较简单,只有几个函数,列举如下。
apc_cache_info () 返回缓存信息
apc_clear_cache() 清除apc缓存内容。
默认(无参数)时,只清除系统缓存,要清除用户缓存,需用‚user‘参数。
apc_define_constants ( string key, array constants [, bool case_sensitive] ) 将数组constants以常量加入缓存。
apc_load_constants (string Key)。
取出常量缓存。
apc_store ( string key, mixed var [, int ttl] )。
在缓存中保存数据。
apc_fetch ( string key )。
获得apc_store保存的缓存内容
apc_delete ( string key )。
删除apc_store保存的内容。
apc的管理:
到pecl.php.net下载apc源码包有个apc.php,copy到你的web server可以访问到的地方,浏览即可访问。
管理界面功能有:
1. Refresh Data
2. View Host Stats
3. System Cache Entries
4. User Cache Entries
5. Version Check
配置php.ini的时候一定要跟进编译选项来放置这些扩展的位置。
默认apc.so要放到php.ini同一个目录下,而不是传说中的extension目录。
Tags : 缓存 , 优化
PHP | 评论 :1
| 阅读 :24148
Submitted by gouki on 2009, May 6, 9:28 AM
本文来自向东的博客:http://www.xiangdong.org/blog/post/1756/
但本人有不同看法。。。
`source` char(255) NOT NULL,
`score` int(11) NOT NULL,
Mysql设置NOT NULL 在pdo插入该字段source为空时候返回false,初看你就奇怪了,为何设置的时候为not null,但是在插入的时候会为null呢?
是这样的,当时开发时候的需求不很明显,但是最后在开发收尾的时候发现这个字段可有可无,而且我们提供的是接口调用,人家就会问了,你这个参数填写什么, 而很有可能就说那个参数啊,可以为空啊,呵呵,这下好了,那个字段刚好可能会出现NULL,和NOT NULL冲突,于是插入数据库出现返回false,而我们又是接口调用,尽量做到给用户返回成功的代码,于是这个插入数据库错误的问题可能会隐藏,最后解 决办法是将数据库source字段改为可以为null!
ALTER TABLE `a` CHANGE `a` `a` INT( 11 ) NOT NULL DEFAULT NULL
ALTER TABLE `a` CHANGE `a` `a` INT( 11 ) NULL DEFAULT NULL
上面这段我还是觉得有问题的,一般情况话,如果设置了NOT NULL,那么default 还是设为0吧。除非你的0在系统中是特殊值。
Tags : pdo
PHP | 评论 :0
| 阅读 :20523
Submitted by gouki on 2009, May 5, 11:09 PM
其实,贴这个文章还有一个用意。不知道大家看过自己的apache的errorlog没,每一次访问,其实浏览器都会查找这个favicon.ico文件,如果没有,就会生成一个404,也就是apache的ErrorLog记录。
而在网页中,一个404会堵塞浏览器的进程挺长时间,所以,在有可能的情况下,还是为自己的网站放上这个文件,一来是为自己的网站做个小广告,二来,也是提高游客的访问速度。
以下是原文:http://blog.goguoguo.com/html/y2009/298.html
作者:土豆
现在很多浏览器都会在地址栏、收藏栏、tab页上面显示一个网站的图标 。这个图标就是你站点根目录下的favicon.ico文件。这是浏览器默认的动作,通过抓包工具可以很明显的看到,如tt浏览器,没有缓存的情况下,打开页面的时候就回去get一下/favicon.ico。
当然也可以显示 去指定,这样的话可以控制ico图片所在的路径,以及这个图片的格式。在html文件中加入如下的代码就好了:
如何方便的来制作这个网站图标 呢,参考如下的一些在线制作的工具,可以省去很大一部分的工作:
国产 制作ico图标 不过生成的ico文件稍微有一点大。
国外 制作ico图标 效果好一些。
更多参考和推荐
车东的博客 还带有图片展示的,可以去看个究竟哦。
备注:
1 上传了ico到你的网站的根目录下后,如果通过地址获取的时候提示你保存的话,说明你的服务器不支持这种类型的mime-type,需要修改一下服务器的配置。
如lighttpd,在mime-type配置下,增加:
“.ico” => “image/x-icon”,
还不行的话,打开这个选项:mimetype.use-xattr = “enable”
2 对于很多服务器的设置都没有明显的针对ico类型的文件来设置过期时间的,由于ico文件很少进行变化,需要将其过期时间设置长一点。我的时一年。
lighttpd中修改配置如下:
$HTTP["url"] =~ “\.ico$” {
expire.url = ( “” => “access 1 years” )
}
3 如果你刷新了浏览器还是看不到你的网站图标的话,你需要清空一下浏览器的cache。重启浏览器试一下。
快去试试吧!
Tags : favicon
PHP | 评论 :0
| 阅读 :21504
Submitted by gouki on 2009, May 5, 7:13 AM
原来以为global和$GLOBALS除了写法不一样以为,其他都一样,可是在实际应用中发现,2者的区别还是很大的!
先看下面的例子:
PHP代码
<?php
function test_global() {
global $var1 , $var2 ;
$var2 =& $var1 ;
}
function test_globals() {
$GLOBALS [ 'var3' ] =& $GLOBALS [ 'var1' ];
}
$var1 = 5;
$var2 = $var3 = 0;
test_global();
print $var2 . "\n" ;
test_globals();
print $var3 . "\n" ;
?>
执行结果为:
0
5
怎么会这样呢?不应该是2个5吗?怎么会出现1个0和1个5呢?
恩,我们保留以上问题,深入分析$GLOBALS和global的原理!
我们都知道变量其实是相应物理内存在代码中的"代号",假设我们上面声明的3个变量分配的内存如下图表示:
引用php手册的$GLOBALS的解释:
Global 变量:$GLOBALS
注意: $GLOBALS 在 PHP 3.0.0 及以后版本中适用。
由所有已定义全局变量组成的数组。变量名就是该数组的索引。
这是一个“superglobal”,或者可以描述为自动全局变量。
也就是说上面代码中的$var1和$GLOBALS['var1']是指的同一变量,而不是2个不同的变量!
下面来分析global到底做了什么?
我们都知道php中的函数所产生的变量都是函数的私有变量,那么global关键字产生的变量也肯定逃不出这个规则,为什么这么说呢,看下面的代码:
PHP代码
<?php
function test() {
global $a ;
unset($a );
}
$a = 1;
test();
print $a ;
?>
复制代码
执行结果为:
1
为什么会输出1呢?不是已经把$a给unset了吗?unset失灵了?php的bug?
都不是,其实unset起作用了,是把test函数中的$a给unset掉了,可以在函数后面加入
print $a;
复制代码
来测试!也就是说global产生了test函数外部$a的别名变量“$a”,为了和外面的$a区别,我把它成为--test->$a,那么例子1也这么命名的话,可得出下面的图:
[没有图,谢谢,忽悠你的]
接着回到上面的例子1,看test_global中的这一代码“$var2 =& $var1;”,上面是一个引用赋值运算,也就是$var2将指向var1所指向的物理内存地址,所以例子1执行过test_global函数以后,变量的变化由下图可以看出:
[没有图,谢谢,忽悠你的]
而test_globals执行过以后,看变量的变化:
此时,看图,就能理解为什么例子1执行完以后,$var2是0,而$var3是5了!
所以我们得出一个结论,在函数中global和$GLOBALS[]的区别在于:
global在函数产生一个指向函数外部变量的别名变量,而不是真正的函数外部变量,一但改变了别名变量的指向地址,就会发生一些意料不到情况,例如例子1.
$GLOBALS[]确确实实调用是外部的变量,函数内外会始终保持一致!
文章来自:向东的博客,http://www.xiangdong.org/blog/post/1749/
Tags : global
PHP | 评论 :10
| 阅读 :44735