一语双关的幽默句子

英语中有好多一语双关的幽默句子,现在为大家摘录一些常用幽默迷你句型,以供参考,据说是流传甚广的加菲猫语录哦。

1. Money is not everything. There’s Mastercard and Visa.

钞票不是万能的,毕竟有时还需要信用卡。

2. One should love animals. They are so tasty.

每个人都应该热爱动物,因为它们很好吃。

3. Save water. Shower with your girlfriend.

要节约用水,所以尽量和女友一起洗澡。

4. Love the neighbor. But don’t get caught.

要用心去爱你的邻居,不过不要让她的老公知道。

5. Behind every successful man, there is a woman. And behind every unsuccessful man, there are two or more.

每个成功男人的背后,都有一个女人。每个不成功男人的背后,都有两个或更多。

6. Every man should marry. After all, happiness is not the only thing in life.

再快乐的单身汉迟早也会结婚,毕竟幸福不是永久的嘛。

7. The wise never marry,and when they marry they become otherwise..

聪明人都是未婚的,结婚的人很难再聪明起来。

8. Success is a relative term. It brings so many relatives.

成功是一个相关名词,它会给你带来很多不相关的亲戚。

9. Never put off the work till tomorrow what you can put off today.

不要等明天交不上差再找借口,今天就要找好。

10. Love is photogenic. It needs darkness to develop.

爱情就像照片,需要大量的暗房时间来培养。

11. Children in backseats cause accidents. Accidents in backseats cause children.

后座上的小孩会生出意外,后座上的意外会生出小孩。

12. “Your future depends on your dreams.”So go to sleep.

现在的梦想决定着你的将来,所以,还是再睡一会吧。

13. There should be a better way to start a day than waking up every morning.

应该有更好的方式开始新的一天,而不是千篇一律地在每个上午都醒来。

14. Hard work never killed any body.But why take the risk?

努力工作不会导致死亡。但为什么要冒险呢?

15. “Work fascinates me.“ I can look at it for hours!

工作好有意思耶!尤其是看着别人工作。

16. God made relatives; Thank God we can choose our friends.

神决定了谁是你的亲戚,幸运的是在选择朋友方面他给了你留了余地。

17. When two’s company, three’s the result!

两个人的状态是不稳定的,三个人才是!

18. A dress is like a barbed fence. It protects the premises without restricting the view.

服饰就象铁丝网,它阻止你冒然行动但并不妨碍你尽情的观看。

19. The more you learn, the more you know, The more you know, the more you forget.The more you forget, the less you know. So why bother to learn.

学的越多,知道的越多, 知道的越多,忘记的越多, 忘记的越多,知道的越少, 为什么学来着。

Freebsd常用命令

vi sshd_config
# rar a all *.jpg
这条命令是将任何.jpg的文档压缩成一个rar包,名为all.rar,该程式会将.rar 扩展名将自动附加到包名后。
# unrar x all.rar
这条命令是将all.rar中的任何文档解压出来
unrar x参数是指定用绝对路径解压缩文件,解压缩出来的路径和压缩文件里面的路径相同!
重启 SSHD 服务usr/ports/archivers/rar

make install clean

#cd /usr/ports/archivers/unrar

#make install clean
命令  /etc/rc.c/sshd restart
光区挂载命令 mount /cdrom  卸载 UMOUNT /CDROM
/usr/local/mysql/bin/mysqld_safe --user=mysql &  mysql 启动命令
很多人都不知道freebsd下如何重启mysql.现在我把命令放到下面,希望对大家有些帮忙。
/usr/local/etc/rc.d/mysql-server restart
/etc/netstart 网卡重启
sh /etc/rc  重新载入配置文件

usr/local/apache/bin/httpd或apachectl start  apache 启动命令
1fsck -y    2sync  3reboot  freebsd 硬盘自检
freebsd 破密码
重启(reboot) 按4 后 mount -a (挂载所有)passwd 更改密码即可 

创建一个webhost用户,对apache和mysql有操作权限

mysql启动命令
/usr/local/etc/rc.d/mysql-server start

通过bpore管理tomcat 
copy <Context path="/probe" docBase="文件路径/probe" debug="0" privileged="true"/>
copy
shutdown –r now 重新启动
apachectl restart 重新启动apeach
chmod -R 777 /www
chmod  755 /www
/usr/local/etc/apache22/httpd.conf
/usr/local/etc/php.ini
问题已经就是那个权限

FreeBSD用户权限管理
几个常用的用户管理命令:
1.显示所有用户: pw usershow -a
2.删除某个用户: pw userdel username
3添加一个用户: pw useradd user (user 为你要添加的用户名)
4.为某个用户加上可写的权限:chown -R user rra/ log/
5.为某一用户添加计划任务:crontab -u user -e然后编辑就行了.
6.删除某一用户的计划任务:crontab -u user -r

要更改文件 program.c 的所有者: 
chown jim program.c
program.c的用户访问权限现在应用到 jim。作为所有者,jim 可以使用 chmod命令允许或拒绝其他用户访问 program.c。
要将目录 /tmp/src 中所有文件的所有者和组更改为用户 john 和组 build: 
chown -R john:build /tmp/src
文件
/usr/bin/chown
 chown命令
我如何改变档案/目录的群组拥有人?s group owner? (chgrp)
我如何改变档案/目录的使用者与群组拥有人? (chown user:group)

有什么方法可以让我慢慢地观看开机记录文件吗? (dmesg |more)
我如何建立一个空档案? (touch)
我如何删除档案? (rm)
我如何建立一个目录? (mkdir)
我如何移除一个空的目录? (rmdir)
我如何移除一个目录包括里面所有的东西 (包括子目录)? (rm -r)
我如何移除以 "-" 起头的档案? (rm -- -filename)
我如何拷贝档案? (cp)
我如何拷贝整个目录包括它所有的内容? (cp -R)
我该如何搬移档案与目录? (mv)
我如何改变档案/目录名称? (mv)
我如何执行 rm、cp 与 mv 时,须要我的许可? (-i)
我如何执行 rm、cp 与 mv 时,不须要我的确认? (-f)
mysql命令行的基本用法(通用linux和windows)
1.注册对FreeBSD 系统作为根, 或 su – 根源 得到对超级用户环境。 2.输入以下在FreeBSD 命令行接口(CLI) (等待直到各个命令完成处理在跑下个命令之前): 光盘/usr/ports/databases/mysql50 服务器 做安装干净 mysql_install_db chown – R mysql /var/db/mysql/ chgrp – R mysql /var/db/mysql/ /usr/local/bin/mysqld_safe – user=mysql & 注: 如果您遇到命令没被发现的错误, 使用命令改作更新OS 道路环境变量。 3.港设施将投入剧本文件mysql-server.sh 在将有能力发动MySQL 服务器的/usr/local/etc/rc.d 。使MySQL 服务器自动地开始在每FreeBSD 服务器reboot, 输入以下在CLI 之后: echo ‘mysql_enable=”YES”‘ > > /etc/ rc.conf 4.MySQL 缺省超级用户帐户- 根- 没有密码(空白的密码) 。如此it’s 重要分配管理员帐户密码。改变密码到根用户, 输入以下: mysqladmin – u 根密码 newpassword 用您自己的渴望的密码替换newpassword 。 5.任意地, 复制或者我huge.cnf, 我large.cnf, 我medim.cnf, 我small.cnf 或我innodb 重4G.cnf (根据MySQL 服务器的用法和运用) 作为my.cnf 对将使您扭捏和改变服务器具体MySQL 服务器选择配置由编辑文件的/var/db/mysql 。 6.MySQL 5.0 设施完成。   04.断电后系统无法启动 a.启动到sing user模式 b.fsck c.reboot 10.挂载ntfs,fat32分区和u盘 ntfs: mount_ntfs -C eucCN /dev/ad0s5 /mnt/d fat32:mount_msdos -L zh_CN.eucCN /dev/ad0s6 /mnt/e u盘:   mount_msdos -L zh_CN.eucCN /dev/da0s1 /mnt/u 11.卸载分区 umount /dev/ad0s5 umount -f /dev/ad0s5 (强制卸载) 12.查看进程 top ps auxww   ps -ef |grep xxx 18.查找程序或文件 whereis 程序名 locate 文件名 whatis xxx 要找东西但不知道它是什么 grep bpf /usr/src/sys/i386/conf/GENERIC 在文件中找指定文本 #只能对文本进行grep,如是命令,则 command |grep text grep text filename b,更新了PATH变量指定目录里可执行命令     rehash 33.磁盘空间使用情形 df 和 du 指令df用来查看整个档案系统的使用情形,如果您需要知道某个目录的使用情形用指令du。 df -h du -h /etc du -sh /etc -s 参数来省略指定目录下的子目录 -h 表示使用GB、MB等易读的格式 34.检视软件间的关联 cd /usr/ports/sysutils/pkg_tree make install clean 之后我们就可以使用 pkg_tree | more 来看各个软件之间的关系了 36.ports安装失败提示 stop in /usr/ports/lang/ruby18/work 删除work目录下所有文件&文件夹再次安装即可. 37.ntop–网络监控软件 cd /usr/ports/net/ntop make install clean vi /etc/rc.conf 加入 ntop_enable=”YES” 在地址栏中输入http://x.x.x.x:3000 即出来管理界面. 41.一次性把所有安装的ports删除掉 a.pkg_delete -a b.安装pkg_cutleaves它会告诉你,哪些package没有人依赖,并让你决定要不要删除

freebsd 添加、删除用户!

2、更改用户登陆shell

默认安装是使用sh登陆的,sh不支持TAB键
要切换到csh,直接运行csh即可

如果需要一劳永逸,那么用下面这个命令
name:是指你登陆的名称
pw usermod -n name -s csh

======================================
添加用户

# pw groupadd vsftpd –g 1001
# pw useradd test –g 1001–d /home/test –s /sbin/nologin

或者

#adduser
Username:用户名
Full name:全名
Uid (Leave empty for default) :要求输入UID值。通常按Enter即可。
Login group [xxxx]:要求输入用户的所属群组。可以输入一个现有的群组,如果保持空白,系统会新建一个与用户名一样的群组。
Login class:登入等級。通常按Enter即可。
Shell (sh csh tcsh zsh ksh bash nologin) [sh]:用户使用的shell,通常按Enter即可。
Home directory [/home/xxxxx]:用户目录,按Enter即可。
Use password-based authentication? [yes]:使用密码认证。当然要。
Use an empty password? (yes/no) [no]:使用空密码。当然不。
Use a random password? (yes/no) [no]:随机生成密码。当然不。
Enter password:密码。注意,输完后屏幕上不会显示任何字符。
Enter password again:确认密码。
Lock out the account after creation? [no]:建立完该帐号后就禁用他。当然不。
最后会出現要求确认的信息:
Username  : xxxx
Password    : *****
Full Name  : xxxx
Uid      : 1001
Class    :
Groups    : xxxx
Home    : /home/ xxxx
Shell    : /bin/sh
Locked    : no
OK? (yes/no):
若一切无误,就输入yes。
Adduser:INFO:Successfully added (xxxx) to the user database.成功
系统会询问是否还要新增其他用户。
Add another user? (yes/no):
若还要新增,就打yes,若不必新增,就打no。
Goodbye!
系统会友好的和你说再见

删除用户:
#rmuser: 删除用户,这个命令会将adduser所建立的一切都删除掉,包括刚刚建立的组。但它不能删除root.

500 OOPS: vsftpd: refusing to run with writable anonymous root

500 OOPS: vsftpd: refusing to run with writable anonymous root

如果我们已经把vsFTPd服务器启动好了,但登录测试是会出现类似下面的提示;

500 OOPS: vsftpd: refusing to run with writable anonymous root

这表示ftp用户的家目录的权限不对,应该改过才对;

[root@localhost ~]# more /etc/passwd |grep ftp
ftp:x:1000:1000:FTP User:/var/ftp:/sbin/nologin

我们发现ftp用户的家目录在/var/ftp,就是这个/var/ftp的权限不对所致,这个目录的权限是不能打开所有权限的;是您运行了chmod 777 /var/ftp所致;如果没有ftp用户这个家目录,当然您要自己建一个;

如下FTP用户的家目录是不能针对所有用户、用户组、其它用户组完全开放;

[root@localhost ~]# ls -ld /var/ftp
drwxrwxrwx 3 root root 4096 2005-03-23 /var/ftp

修正这个错误,应该用下面的办法;

[root@localhost ~]# chown root:root /var/ftp
[root@localhost ~]# chmod 755 /var/ftp

有的弟兄可能会说,那匿名用户的可读、可下载、可上传怎么办呢?这也简单,在/var/ftp下再建一个目录,权限是777的就行了,再改一改vsftpd.conf就OK了;没有什么难的;

vsFTPd出于安全考虑,是不准让ftp用户的家目录的权限是完全没有限制的,您可以去读一下vsFTPd的文档就明白的了;否则也不能称为最安全的FTP服务器了,对不对?

FREEBSD:VSFTP的安装和配置(packages方式)

一、预备工作:
1.新建目录
mkdir /usr/share/empty
mkdir /var/ftp
2.改变目录所有者和权限
chown root:wheel /var/ftp(如果是Linux用chown root:root /var/ftp)
chmod og-w /var/ftp (此命令是取消其他用户的写权限)
二、安装VSFTP
1.用tar包安装
tar zvf vsftpd-2.0.1.gz.tar
cd vsfpd-2.0.1
make
make install
2.用ports安装(只适合FREEBSD,而且必须是可以上网的用户,对Linux用户不适用)
cd /usr/ports/ftp/vsftpd
make
make install
安装的时候会弹出一个对话框,


选中第一个选项项
三、配置
1.配置VSFTP
打开/etc/vsftpd.conf,(如果用ports安装的话是在/usr/local/etc/vsftpd.conf),,相关参数说明如下:
===个别使用者设定===================
chroot_list_enable
用法:YES/NO
如果启动这项功能,则所有的本机使用者登入均可进到根目录之外的数据夹,除了列在/etc/vsftpd.chroot_list 之中的使用者之外。默认值为NO。
userlist_enable
用法:YES/NO
若是启动此功能,则会读取/etc/vsftpd.user_list 当中的使用者名称。此项功能可以在询问密码前就出现失败讯息,而不需要检验密码的程序。默认值为关闭。
userlist_deny
用法:YES/NO
这个选项只有在userlist_enable 启动时才会被检验。如果将这个选项设为YES,则在/etc/vsftpd.user_list 中的使用者将无法登入 若设为NO , 则只有在/etc/vsftpd.user_list 中的使用者才能登入。而且此项功能可以在询问密码前就出现错误讯息,而不需要检验密码的程序。
user_config_dir
定义个别使用者设定文件所在的目录,例如定义user_config_dir=/etc/vsftpd/userconf,且主机上有使用者test1,test2,那我们可以在user_config_dir 的目录新增文件名为test1 以及test2。若是test1 登入,则会读取user_config_dir 下的test1 这个档案内的设定。默认值为无。
===欢迎语设定=====================
dirmessage_enable
如果启动这个选项,使用者第一次进入一个目录时,会检查该目录下是否有.message这个档案,若是有,则会出现此档案的内容,通常这个档案会放置欢迎话语,或是对该目录的说明。默认值为开启。
banner_file
当使用者登入时,会显示此设定所在的档案内容,通常为欢迎话语或是说明。默认值为无。
ftpd_banner
这边可定义欢迎话语的字符串,相较于banner_file 是档案的形式,而ftpd_banner 是字串的格式。预设为无。
===特殊安全设定====================
chroot_local_user
如果设定为YES,那么所有的本机的使用者都可以切换到根目录以外的数据夹。预设值为NO。
hide_ids
如果启动这项功能,所有档案的拥有者与群组都为ftp,也就是使用者登入使用ls -all之类的指令,所看到的档案拥有者跟群组均为ftp。默认值为关闭。
ls_recurse_enable
若是启动此功能,则允许登入者使用ls -R 这个指令。默认值为NO。
write_enable
用法:YES/NO
这个选项可以控制FTP 的指令是否允许更改file system,譬如STOR、DELE、RNFR、RNTO、MKD、RMD、APPE 以及SITE。预设是关闭。
setproctitle_enable
用法:YES/NO
启动这项功能,vsftpd 会将所有联机的状况已不同的process 呈现出来,换句话说,使用ps -ef 这类的指令就可以看到联机的状态。默认值为关闭。
tcp_wrappers
用法:YES/NO
如果启动,则会将vsftpd 与tcp wrapper 结合,也就是可以在/etc/hosts.allow 与/etc/hosts.deny 中定义可联机或是拒绝的来源地址。
pam_service_name
这边定义PAM 所使用的名称,预设为vsftpd。
secure_chroot_dir
这个选项必须指定一个空的数据夹且任何登入者都不能有写入的权限,当vsftpd 不需要file system 的权限时,就会将使用者限制在此数据夹中。默认值为/usr/share/empty
===纪录文件设定=====================
xferlog_enable
用法:YES/NO
如果启动,上传与下载的信息将被完整纪录在底下xferlog_file 所定义的档案中。预设为开启。
xferlog_file
这个选项可设定纪录文件所在的位置,默认值为/var/log/vsftpd.log。
xferlog_std_format
如果启动,则纪录文件将会写为xferlog 的标准格式,如同wu-ftpd 一般。默认值为关闭。
===逾时设定======================
accept_timeout
接受建立联机的逾时设定,单位为秒。默认值为60。
connect_timeout
响应PORT 方式的数据联机的逾时设定,单位为秒。默认值为60。
data_connection_timeout
建立数据联机的逾时设定。默认值为300 秒。
idle_session_timeout
发呆的逾时设定,若是超出这时间没有数据的传送或是指令的输入,则会强迫断线,单位为秒。默认值为300。
===速率限制======================
anon_max_rate
匿名登入所能使用的最大传输速度,单位为每秒多少bytes,0 表示不限速度。默认值为0。
local_max_rate
本机使用者所能使用的最大传输速度,单位为每秒多少bytes,0 表示不限速度。预设值为0。
===新增档案权限设定==================
anon_umask
匿名登入者新增档案时的umask 数值。默认值为077。
file_open_mode
上传档案的权限,与chmod 所使用的数值相同。默认值为0666。
local_umask
本机登入者新增档案时的umask 数值。默认值为077。
===port 设定======================
connect_from_port_20
用法:YES/NO
若设为YES,则强迫ftp-data 的数据传送使用port 20。默认值为YES。
ftp_data_port
设定ftp 数据联机所使用的port。默认值为20。
listen_port
FTP server 所使用的port。默认值为21。
pasv_max_port
建立资料联机所可以使用port 范围的上界,0 表示任意。默认值为0。
pasv_min_port
建立资料联机所可以使用port 范围的下界,0 表示任意。默认值为0。
===其它========================
anon_root
使用匿名登入时,所登入的目录。默认值为无。
local_enable
用法:YES/NO
启动此功能则允许本机使用者登入。默认值为YES。
local_root
本机使用者登入时,将被更换到定义的目录下。默认值为无。
text_userdb_names
用法:YES/NO
当使用者登入后使用ls -al 之类的指令查询该档案的管理权时,预设会出现拥有者的UID,而不是该档案拥有者的名称。若是希望出现拥有者的名称,则将此功能开启。默认值为NO。
pasv_enable
若是设为NO,则不允许使用PASV 的模式建立数据的联机。默认值为开启。
===更换档案所有权===================
chown_uploads
用法:YES/NO
若是启动,所有匿名上传数据的拥有者将被更换为chown_username 当中所设定的使用者。这样的选项对于安全及管理,是很有用的。默认值为NO。
chown_username
这里可以定义当匿名登入者上传档案时,该档案的拥有者将被置换的使用者名称。预设值为root。
===guest 设定=====================
guest_enable
用法:YES/NO
若是启动这项功能,所有的非匿名登入者都视为guest。默认值为关闭。
guest_username
这里将定义guest 的使用者名称。默认值为ftp。
===anonymous 设定==================
anonymous_enable
用法:YES/NO
管控使否允许匿名登入,YES 为允许匿名登入,NO 为不允许。默认值为YES。
no_anon_password
若是启动这项功能,则使用匿名登入时,不会询问密码。默认值为NO。
anon_mkdir_write_enable
用法:YES/NO
如果设为YES,匿名登入者会被允许新增目录,当然,匿名使用者必须要有对上层目录的写入权。默认值为NO。
anon_other_write_enable
用法:YES/NO
如果设为YES,匿名登入者会被允许更多于上传与建立目录之外的权限,譬如删除或是更名。默认值为NO。
anon_upload_enable
用法:YES/NO
如果设为YES,匿名登入者会被允许上传目录的权限,当然,匿名使用者必须要有对上层目录的写入权。默认值为NO。
anon_world_readable_only
用法:YES/NO
如果设为YES,匿名登入者会被允许下载可阅读的档案。默认值为YES。
ftp_username
定义匿名登入的使用者名称。默认值为ftp。
deny_email_enable
若是启动这项功能,则必须提供一个档案/etc/vsftpd.banner_emails,内容为email address。若是使用匿名登入,则会要求输入email address,若输入的email address 在此档案内,则不允许联机。默认值为NO。
===Standalone 选项==================
listen
用法:YES/NO
若是启动,则vsftpd 将会以独立运作的方式执行,若是vsftpd 独立执行,如RedHat9的默认值,则必须启动 若是vsftpd 包含在xinetd 之中,则必须关闭此功能,如RedHat8。在RedHat9 的默认值为YES。
listen_address
若是vsftpd 使用standalone 的模式,可使用这个参数定义使用哪个IP address 提供这项服务,若是主机上只有定义一个IP address,则此选项不需使用,若是有多个IPaddress,可定义在哪个IP address 上提供ftp 服务。若是不设定,则所有的IP address均会提供此服务。默认值为无。
max_clients
若是vsftpd 使用standalone 的模式,可使用这个参数定义最大的总联机数。超过这个数目将会拒绝联机,0 表示不限。默认值为0。
max_per_ip
若是vsftpd 使用standalone 的模式,可使用这个参数定义每个ip address 所可以联机的数目。超过这个数目将会拒绝联机,0 表示不限。默认值为0。

2.添加用户(FREEBSD系统使用adduser命令,Linux系统用useradd)
1.新建匿名用户
adduser -d /var/ftp ftp
2.新建普通用户,这里就用test1
adduser -d /var/ftp test1 (Linux系统使用useradd -d /var/ftp)
四.启动服务
1.配置inetd
打开/etc/inetd.conf,并添加下面一行
ftp stream tcp nowait root /usr/sbin/tcpd /usr/local/sbin/vsftpd
现在重新启动inted服务,让配置生效
killall –HUP inetd

附:
FTP 数字代码的意义
110 重新启动标记应答。
120 服务在多久时间内ready。
125 数据链路埠开启,准备传送。
150 文件状态正常,开启数据连接端口。
200 命令执行成功。
202 命令执行失败。
211 系统状态或是系统求助响应。
212 目录的状态。
213 文件的状态。
214 求助的讯息。
215 名称系统类型。
220 新的联机服务ready。
221 服务的控制连接埠关闭,可以注销。
225 数据连结开启,但无传输动作。
226 关闭数据连接端口,请求的文件操作成功。
227 进入passive mode。
230 使用者登入。
250 请求的文件操作完成。
257 显示目前的路径名称。
331 用户名称正确,需要密码。
332 登入时需要账号信息。
350 请求的操作需要进一部的命令。
421 无法提供服务,关闭控制连结。
425 无法开启数据链路。
426 关闭联机,终止传输。
450 请求的操作未执行。
451 命令终止:有本地的错误。
452 未执行命令:磁盘空间不足。
500 格式错误,无法识别命令。
501 参数语法错误。
502 命令执行失败。
503 命令顺序错误。
504 命令所接的参数不正确。
530 未登入。
532 储存文件需要账户登入。
550 未执行请求的操作。
551 请求的命令终止,类型未知。
552 请求的文件终止,储存位溢出。
553 未执行请求的的命令,名称不正确

freebsd 7.0 vsftpd如何启动!!

etc/rc.conf中添加
vsftpd_enable=”YES”

/usr/local/etc/vsftpd.conf中添加

listen=YES
background=YES

就可以了,还真是挺复杂,每个软件安装了都要修改配置文件才能启动!!
如果出现错误

500 OOPS: vsftpd: cannot locate user specified in ‘ftp_username’:ftp在vsftpd.conf中加入了ftp_username=xxx(用户)

以下命令可以用来重启vsftpd服务
# /usr/local/etc/rc.d/vsftpd restart

[教程]FreeBSD下vsftp安装配置详解(ports方式)

FreeBSD功能强大,ftp服务器只是它其中的很基础的一种服务,但是作为日常的服务器运作ftp服务却是必不可少,本篇是本人自己在学习FreeBSD的服务器设置过程中的一些积累,因为自己也曾是由菜鸟入门,走了不少弯路,现在把自己的一些经验总结出来,供大家参考,希望对新人能有所帮助,不足之处还请大家多多指点.

1、安装

通过ports安装,这个方式比较简单。

# cd /usr/ports/ftp/vsftpd
# make install


安装过程中会弹出一个对话框架,选中第一个选项,我以前没有选中,结果安装完以后,在/usr/local/etc/rc.d/目录里没有vsftpd这个命令,导致启动的时候出现以下错误信息:
”500 OOPS: vsftpd: cannot open config file:start”

2、配置

/usr/local/etc/vsftpd.conf文件一般按以下配置就差不多了:

anonymous_enable=NO

local_enable=YES

write_enable=YES

local_umask=022

chroot_list_enable=YES (开启锁定用户目录)

listen=YES

background=YES

(1)编辑/usr/local/etc/vsftpd.conf

# ee /usr/local/etc/vsftpd.conf

Anonymous_enable=NO (禁止匿名登陆)

Local_enable=YES (允许本地用户登陆)

Local_umask=022 (FTP上本地的文件权限755,默认是077)

Connect_form_port_20=yes (启用FTP数据端口的数据连接)

Xferlog_enable=yes (激活上传和下传的日志)

Xferlog_std_format=yes (使用标准的日志格式)

Idle_session_timeout=120(秒) (用户会话空闲后2分钟)

Data_connection_timeout=300(秒) (将数据连接空闲5分钟断)

Ascii_upload_enable=YES (起用ASCII方式上传)

Ascii_download_enable=YES帮带(起用ASCII方式下载)

Ftpd_banner=Welcome to blah FTP service. (FTP服务器登陆欢迎信息)

Chroot_list_enable=YES (开启锁定用户目录)

Chroot_list_file=/任意路径/vsftpd.chroot_list (开启锁定用户目录后,凡在这个文件里出现的用户名都不起使用,格式为每个用户一行,要与Chroot)_list_enable=YES 配对使用)

注:如果想把本地的任何用户都锁定在自己的目录中的话,把上面两行(Chroot_list_enable 和 Chroot_list_file)注释掉,再增加这一样

Chroot_local_user=YES

保存退出

(2)编辑/etc/inetd.conf

# ee /etc/inetd.conf

增加这一行并去掉前面的注释(#号)

#ftp   stream tcp    nowait root    /usr/local/libexec/vsftpd     vsftpd

保存退出

(3)编辑/etc/rc.conf

# ee /etc/rc.conf

增加下面内容:

inetd_enable=”YES”

注:以上是以inetd的方式启动vsftp的,我们也可以以独立进程的方式启动vsftp,具体如下:

a、注释掉inetd里面的vsftpd这一行。

b、在vsftpd.conf文件里增加

listen=YES
background=YES

c、启用ftp服务:

#/usr/local/etc/rc.d/vsftpd restart

或者

#/usr/local/libexec/vsftpd &

d、想要让vsftp随系统启动,这里有两种方法:
法一:在/etc/rc.conf文件里添加

vsftpd_enable=”YES”.

法二:在/usr/local/etc/rc.d/目录里增加一个sh脚本:

# vi vsftpd_start.sh

# ! /bin/sh

/usr/local/libexec/vsftpd &

保存退出,再chmod 755 vsftpd_start.sh 。

(4)添加用户

# pw groupadd vsftpd –g 1001

# pw useradd test –g 1001–d /home/test –s /sbin/nologin

# mkdir /home/test

# passwd test               设密码

Changing local password for test

New Password:

Retype New Password:

#

上面的 -d /home/test 为用户的默认默认,这里改为ftp目录的路径,这样用户直接登录后的位置就是ftp的位置了.

vsftpd.chroot_list文件里增加 test 一行,把test用户锁在其自家目录下。

#touch /etc/vsftpd.chroot_list
#echo ‘test’  >> /etc/vsftpd.chroot_list

# killall -HUP inetd,(如果是独立进程则执行上面写的那个脚本即可)测试一下:

# ftp localhost

如果成功会提示你输入用户名和密码

如果不成功,请查看一下你上面的配置

一般不成功是由于权限引起的问题,如无法上传文件,此时可以用ls -al查看一下FTP文件夹的详细权限,一般设置文件的权限为
-rw- r– r- –

就可以了.

看文件夹所有者是不是ftp用户组里的用户,还是用户组是不是正确的,如果说不正确可以用chmod命令修改一下所有者,如修改文件haohtmlcom文件夹的所有都是vsftpd用户组里的test用户,执行#chmod -R 701 /usr/local/www/haohtmlcom命令即可,这样此文件夹只能允许vsftpd组里的test用户访问,组中的其它用户无法进行访问(700),当然也可以设置其它用户组里用户,这种情况一般用于为一个站点开设两个ftp用户时使用,只需要执行#chmod -R 771 /usr/local/www/haohtmlcom即可.上面的-R参数是为了所权限应用到子目录,不然只能当前目录起作用的,无法达到用户的使用要求.

#chown -R test:vsftpd /
usr/local/www/haohtmlcom
如果还不行请参考:http://blog.haohtml.com/index.php/archives/2682

启动vsftp服务
# /usr/local/etc/rc.d/vsftpd restart

(5)用户功能权限配置

以下是一些用户的配置:

Anonymous_enable=yes (允许匿名登陆)

Dirmessage_enable=yes (切换目录时,显示目录下.message的内容)

Local_umask=022 (FTP上本地的文件权限,默认是077)

Connect_form_port_20=yes (启用FTP数据端口的数据连接)

Xferlog_enable=yes (激活上传和下传的日志)

Xferlog_std_format=yes (使用标准的日志格式)

Ftpd_banner=XXXXX (欢迎信息)

Pam_service_name=vsftpd (验证方式)

Listen=yes (独立的VSFTPD服务器)

Anon_upload_enable=yes (开放上传权限)

Anon_mkdir_write_enable=yes (可创建目录的同时可以在此目录中上传文件)

Write_enable=yes (开放本地用户写的权限)

Anon_other_write_enable=yes (匿名帐号可以有删除的权限)

Anon_world_readable_only=no (放开匿名用户浏览权限)

Idle_session_timeout=600(秒) (用户会话空闲后10分钟)

Data_connection_timeout=120(秒) (将数据连接空闲2分钟断)

Accept_timeout=60(秒) (将客户端空闲1分钟后断)

注意:此方法好像一般不用的,为了安全一般在vsftpd下创建虚拟用户的方法的,详见:FreeBSD vsftpd+pam虚拟用户方案配置

7.6. 分发器 第 7 章 Zend_Controller

7.6. 分发器

7.6.1. 概述

分发是取得请求对象,提取其中的模块名,控制器名,动作名以及可选参数,然后实例化控制器并调用其中的动作的整过过程。如果其中的模块、控制器或者动作没能找到,将使用它们的默认值。Zend_Controller_Dispatcher_Standard指定每个控制器和动作的默认值为 index,模块的默认值为default,允许开发人通过setDefaultController()setDefaultAction()setDefaultModule()改变默认值设定。

[注意] 缺省模块
当创建模块程序,你可能也需要缺省模块的命名空间(缺省配置中,缺省模块没有命名空间)。从 1.5.0 开始,可以在前端控制器或你的派遣器里通过指定 prefixDefaultModule 为 true 来实现。

<?php 
// In your front controller:
$front->setParam('prefixDefaultModule', true);

// In your dispatcher:
$dispatcher->setParam('prefixDefaultModule', true);
?>

这允许你重定义一个已存在的模块为程序的缺省模块。

分发发生在前端控制器中的一个循环(loop)中。分发之前,前端控制器通过路由请求,找到用户指定的模块、控制器、动作和可选参数。然后进入分发循环,分发请求。

每次迭代(iteration)过程开始时,在请求对象中设置一个标志指示该动作已分发。如果在动作或者前/后分发(pre/postDispatch)插件重置了该标志,分发循环将继续下去并试图分发新的请求。通过改变请求中的控制器或者动作并重置已分发标志,开发人员可以定制执行一个请求链。

控制这种分发过程的动作控制器方法是_forward();在任意的pre/postDispatch()或者动作中调用该方法,并传入动作、控制器、模块、以及可选的附加参数,就可以进入新的动作。

<?php
public function fooAction()
{
    // forward to another action in the current controller and module:
    $this->_forward('bar', null, null, array('baz' => 'bogus'));
}

public function barAction()
{
    // forward to an action in another controller, FooController::bazAction(),
    // in the current module:
    $this->_forward('baz', 'foo', null, array('baz' => 'bogus'));
}

public function bazAction()
{
    // forward to an action in another controller in another module,
    // Foo_BarController::bazAction():
    $this->_forward('baz', 'bar', 'foo', array('baz' => 'bogus'));
}

7.6.2. 子类化分发器

Zend_Controller_Front首先调用路由器找到请求中的第一个动作,然后进入分发循环,调用分发器分发动作。

分发器需要大量数据完成任务——它需要知道如何格式化控制器和动作的名称,到哪儿找到控制器类文件,模块名是否有效,以及基于其它可用信息判定请求是否能分发的API。

Zend_Controller_Dispatcher_Interface定义了下列所有分发器需要实现的方法。

interface Zend_Controller_Dispatcher_Interface
{
    /**
     * Format a string into a controller class name.
     *
     * @param string $unformatted
     * @return string
     */
    public function formatControllerName($unformatted);

    /**
     * Format a string into an action method name.
     *
     * @param string $unformatted
     * @return string
     */
    public function formatActionName($unformatted);

    /**
     * Determine if a request is dispatchable
     *
     * @param  Zend_Controller_Request_Abstract $request
     * @return boolean
     */
    public function isDispatchable(Zend_Controller_Request_Abstract $request);

    /**
     * Set a user parameter (via front controller, or for local use)
     *
     * @param string $name
     * @param mixed $value
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function setParam($name, $value);

    /**
     * Set an array of user parameters
     *
     * @param array $params
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function setParams(array $params);

    /**
     * Retrieve a single user parameter
     *
     * @param string $name
     * @return mixed
     */
    public function getParam($name);

    /**
     * Retrieve all user parameters
     *
     * @return array
     */
    public function getParams();

    /**
     * Clear the user parameter stack, or a single user parameter
     *
     * @param null|string|array single key or array of keys for params to clear
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function clearParams($name = null);

    /**
     * Set the response object to use, if any
     *
     * @param Zend_Controller_Response_Abstract|null $response
     * @return void
     */
    public function setResponse(Zend_Controller_Response_Abstract $response = null);

    /**
     * Retrieve the response object, if any
     *
     * @return Zend_Controller_Response_Abstract|null
     */
    public function getResponse();

    /**
     * Add a controller directory to the controller directory stack
     *
     * @param string $path
     * @param string $args
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function addControllerDirectory($path, $args = null);

    /**
     * Set the directory (or directories) where controller files are stored
     *
     * @param string|array $dir
     * @return Zend_Controller_Dispatcher_Interface
     */
    public function setControllerDirectory($path);

    /**
     * Return the currently set directory(ies) for controller file lookup
     *
     * @return array
     */
    public function getControllerDirectory();

    /**
     * Dispatch a request to a (module/)controller/action.
     *
     * @param  Zend_Controller_Request_Abstract $request
     * @param  Zend_Controller_Response_Abstract $response
     * @return Zend_Controller_Request_Abstract|boolean
     */
    public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response);

    /**
     * Whether or not a given module is valid
     *
     * @param string $module
     * @return boolean
     */
    public function isValidModule($module);
}

不过大多数情况下,只需要简单地扩展抽象类Zend_Controller_Dispatcher_Abstract,其中已经定义好了上面的大部分方法。或者扩展Zend_Controller_Dispatcher_Standard类,基于标准分发器来修改功能。

需要子类化分发器的可能原因包括:期望在动作控制器中使用不同的类和方法命名模式,或者期望使用不同的分发方式,比如分发到控制器目录下的动作文件,而不是控制器类的动作方法。

7.11. 使用传统的模块目录结构 第 7 章 Zend_Controller

7.11. 使用传统的模块目录结构

7.11.1. 简介

传统的模块目录结构允许你把不同的MVC应用程序分离成为独立的单元,并和不同的前端控制器配合再使用。示例一下这样的目录结构:

docroot/
    index.php
application/
    default/
        controllers/
            IndexController.php
            FooController.php
        models/
        views/
            scripts/
                index/
                foo/
            helpers/
            filters/
    blog/
        controllers/
            IndexController.php
        models/
        views/
            scripts/
                index/
            helpers/
            filters/
    news/
        controllers/
            IndexController.php
            ListController.php
        models/
        views/
        views/
            scripts/
                index/
                list/
            helpers/
            filters/

在这个范例中,模块名作为它所包含的控制器的前缀。上面的例子包含三个模块控制器:’Blog_IndexController’ ‘News_IndexController’ 和’News_ListController’。也定义了两个全局控制器:’IndexController’ 和 ‘FooController’。它们都将不需要命名空间前缀。这个目录结构在本章中用作为例子。

[注意] 在缺省模块中不用命名空间前缀
注意在缺省模块中,控制器不需要一个命名空间前缀。这样,在上例中,在缺省模块中的控制器不需要’Default_’这样的前缀--根据它们的基本控制器名’IndexController’ 和 ‘FooController’被简单地派遣。然而,命名空间前缀被用于所有其它模块。

那么,你怎样用Zend Framework MVC组件来实现这样的目录结构?

7.11.2. 指定模块控制器目录

利用模块的第一步是来修改你如何在前端控制器指定控制器目录列表。在基本的MVC系列,传递数组或字符串给setControllerDirectory(),或者传递路径给addControllerDirectory()。当使用模块,你需要稍微修改对这些方法的调用。

setControllerDirectory(),你将需要传递一个关联数组和指定‘模块名/目录路径’的‘键/值’对。特殊的键default 将被用作全局控制器(不需要模块命名空间)。所有条目应该包含指向一个单个路径的字符串键,并且default键必须出现。例如:

<?php
$front->setControllerDirectory(array(
      'default' => '/path/to/application/controllers',
      'blog'    => '/path/to/application/blog/controllers'
));

addControllerDirectory()将带有可选的第二个参数。当使用模块,传递模块名作为第二个参数;如果没有指定,路径将被加到default命名空间。例如:

<?php
$front->addControllerDirectory('/path/to/application/news/controllers', 'news');

把最好的保留到最后,指定模块的最容易的方法是整体来做,把所有模块放到一个通用的目录并使用相同的结构。这可以用addModuleDirectory()来完成:

<?php
/**
 * Assuming the following directory structure:
 * application/
 *     modules/
 *         default/
 *             controllers/
 *         foo/
 *             controllers/
 *         bar/
 *             controllers/
 */
$front->addModuleDirectory('/path/to/application/modules');

上面的例子将定义defaultfoobar模块,每个都分别指向它们的模块的controllers子目录。

你可以在模块中通过setModuleControllerDirectoryName()来定制模块子目录:

<?php
/**
 * Change the controllers subdirectory to be 'con'
 * application/
 *     modules/
 *         default/
 *             con/
 *         foo/
 *             con/
 *         bar/
 *             con/
 */
$front->setModuleControllerDirectoryName('con');
$front->addModuleDirectory('/path/to/application/modules');
[注意] 注意
你可以通过传递一个空值给setModuleControllerDirectoryName()来指定在你的模块中没有控制器子目录。

7.11.3. Routing to modules

Zend_Controller_Router_Rewrite中缺省的路由是一个Zend_Controller_Router_Route_Module类型的对象。这个路由使用下面路由计划之一:

  • :module/:controller/:action/*
  • :controller/:action/*

换句话说,它将自己或通过先前的模块来匹配控制器和动作。匹配规则指定一个模块将只匹配在传递给前端控制器和派遣器的控制器目录数组中存在同名的键。

7.11.4. 模块或全局缺省控制器

在缺省的路由器中,如果在URL中没有指定控制器,缺省控制器就被使用(IndexController,除非另外要求)。对于模块控制器,如果一个模块被指定但没有控制器,派遣器首先寻找在这个模块路径中的缺省控制器,然后回到在’default’、全局、命名空间中发现的缺省控制器。

如果你总愿意缺省到全局命名空间,在前端控制器中设置useDefaultControllerAlways 参数:

<?php
$front->setParam('useDefaultControllerAlways', true);

php构造函数和析构函数

构造函数
void __construct ([ mixed $args [, $… ]] )
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。

Note: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。

Example#1 使用新标准的构造函数

class BaseClass {
function __construct() {
print “In BaseClass constructor\n”;
}
}

class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print “In SubClass constructor\n”;
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>
为了实现向后兼容性,如果 PHP 5 在类中找不到 __construct() 函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法,但它却又不是构造函数。

析构函数
void __destruct ( void )
PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

Example#2 析构函数示例

class MyDestructableClass {
function __construct() {
print “In constructor\n”;
$this->name = “MyDestructableClass”;
}

function __destruct() {
print “Destroying ” . $this->name . “\n”;
}
}

$obj = new MyDestructableClass();
?>
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。

Note: 析构函数在脚本关闭时调用,此时所有的头信息已经发出。

Note: 试图在析构函数中抛出一个异常会导致致命错误。

访问控制 自动加载对象
——————————————————————————–
Last updated: Sun, 25 Nov 2007

add a note User Contributed Notes
构造函数和析构函数
Jeffrey
09-Oct-2008 02:04
Constructor Simplicity

If your class DOES CONTAIN instance members (variables) that need to be set, then your class needs to be initialized… and you should use __construct() to do that.

class MyClassA {
public $data1, $data2;

public function __construct($mcd1, $mcd2) {
$this->data1 = $mcd1; // INITIALIZE $data1
$this->data2 = $mcd2; // INITIALIZE $data2
}
}

$obj1 = new MyClassA(“Hello”, “World!”); // INSTANTIATE MyClassA
$d1 = $obj1->data1;
$d2 = $obj1->data2;
?>

If your class DOES NOT CONTAIN instance members or you DO NOT want to instantiate it, then there is no reason to initialize it or use __construct().

class MyClassB {
const DATA1 = “Hello”;
public static $data2 = “World!”;
}

$obj1 = new MyClassB(); // INSTANTIATE MyClassB – NO error.
$d1 = $obj1::DATA1; // ERROR
$d2 = $obj1::data2; // ERROR
$d1 = MyClassB::DATA1; // ok
$d2 = MyClassB::$data2; // ok
?>

The fact that $obj1 is useless and cannot be used as a reference, is further evidence that MyClassB objects should not be instantiated. NOTICE that MyClassB does not use private members or functions to make it behave that way. Rather, it is the collective nature of all the class members + what ISN’T there.
Anonymous
09-Sep-2008 05:42
USE PARENT::CONSTRUCT() to exploit POLYMORPHISM POWERS

Since we are still in the __construct and __destruct section, alot of emphasis has been on __destruct – which I know nothing about. But I would like to show the power of parent::__construct for use with PHP’s OOP polymorphic behavior (you’ll see what this is very quickly).

In my example, I have created a fairly robust base class that does everything that all subclasses need to do. Here’s the base class def.

/*
* Animal.php
*
* This class holds all data, and defines all functions that all
* subclass extensions need to use.
*
*/
abstract class Animal
{
public $type;
public $name;
public $sound;

/*
* called by Dog, Cat, Bird, etc.
*/
public function __construct($aType, $aName, $aSound)
{
$this->type = $aType;
$this->name = $aName;
$this->sound = $aSound;
}

/*
* define the sorting rules – we will sort all Animals by name.
*/
public static function compare($a, $b)
{
if($a->name < $b->name) return -1;
else if($a->name == $b->name) return 0;
else return 1;
}

/*
* a String representation for all Animals.
*/
public function __toString()
{
return “$this->name the $this->type goes $this->sound”;
}
}

?>

Trying to instantiate an object of type Animal will not work…

$myPet = new Animal(“Parrot”, “Captain Jack”, “Kaaawww!”); // throws Fatal Error: cannot instantiate abstract class Animal.

Declaring Animal as abstract is like killing two birds with one stone. 1. We stop it from being instantiated – which means we do not need a private __construct() or a static getInstance() method, and 2. We can use it for polymorphic behavior. In our case here, that means “__construct”, “__toString” and “compare” will be called for all subclasses of Animal that have not defined their own implementations.

The following subclasses use parent::__construct(), which sends all new data to Animal. Our Animal class stores this data and defines functions for polymorphism to work… and the best part is, it keeps our subclass defs super short and even sweeter.

class Dog extends Animal{
public function __construct($name){
parent::__construct(“Dog”, $name, “woof!”);
}
}

class Cat extends Animal{
public function __construct($name){
parent::__construct(“Cat”, $name, “meeoow!”);
}
}

class Bird extends Animal{
public function __construct($name){
parent::__construct(“Bird”, $name, “chirp chirp!!”);
}
}

# create a PHP Array and initialize it with Animal objects
$animals = array(
new Dog(“Fido”),
new Bird(“Celeste”),
new Cat(“Pussy”),
new Dog(“Brad”),
new Bird(“Kiki”),
new Cat(“Abraham”),
new Dog(“Jawbone”)
);

# sort $animals with PHP’s usort – calls Animal::compare() many many times.
usort($animals, array(“Animal”, “compare”));

# print out the sorted results – calls Animal->__toString().
foreach($animals as $animal) echo “$animal
\n”;

?>

The results are “sorted by name” and “printed” by the Animal class:

Abraham the Cat goes meeoow!
Brad the Dog goes woof!
Celeste the Bird goes chirp chirp!!
Fido the Dog goes woof!
Jawbone the Dog goes woof!
Kiki the Bird goes chirp chirp!!
Pussy the Cat goes meeoow!

Using parent::__construct() in a subclass and a super smart base class, gives your child objects a headstart in life, by alleviating them from having to define or handle several error and exception routines that they have no control over.

Notice how subclass definitions are really short – no variables or functions at all, and there is no private __construct() method anywhere? Notice how objects of type Dog, Cat, and Bird are all sorted by our base class Animal? All the class definitions above address several issues (keeping objects from being instantiated) and enforces the desired, consistent, and reliable behavior everytime… with the least amount of code. In addition, new extenstions can easily be created. Each subclass is now super easy to redefine or even extend… now that you can see a way to do it.
KK
16-May-2008 01:57
I ran into an interesting (and subtle) code error while porting some code to PHP 5.2.5 from PHP 4.4.8 that I think illustrates a noteworthy semantic.

I have a hierarchy of classes with both styles of constructors but where one in the middle was missing the __construct() function (it just had the old-style one that called the (nonexistent) __construct()). It worked fine in PHP4 but caused an endless loop (and stack overflow) in PHP5. I believe what happened is that in PHP4 the old-style constructor was not called, but in PHP5 it was (due to the “emulation” of PHP4), and since _construct() wasn’t defined for that class, the call to $this->__construct() caused a looping call to the original (lowest child) constructor.
bolshun at mail dot ru
16-Apr-2008 06:13
Ensuring that instance of some class will be available in destructor of some other class is easy: just keep a reference to that instance in this other class.
ashnazg at php dot net
12-Apr-2008 10:26
Since my last note, I’ve been instructed to _NEVER_ call “unset($this)”, never ever ever. Since my previous testing of behavior did not explicitly show me that it was indeed necessary, I’m inclined to trust those telling me not to do it.
ashnazg at php dot net
28-Feb-2008 02:39
While experimenting with destructs and unsets in relation to memory usage, I found what seems to be one useful way to predict when __destruct() gets called… call it manually yourself.

I had previously assumed that explicitly calling unset($foo) would cause $foo->__destruct() to run implicitly, but that was not the behavior I saw (php 5.2.5). The destructors weren’t running until the script ended, even though I was calling unset($foo) in the middle of my script. So, having $foo->__destruct() unset all of $foo’s component objects was not helping my memory usage since my explicit unset($foo) was _not_ triggering $foo->__destruct()’s cleanup steps.

Interestingly, what _did_ appear to happen is that calling unset($bar) from inside a destructor like $foo->__destruct() _DID_ cause $bar->__destruct() to be implicitly executed. Perhaps this is because $bar has a “parent” reference of $foo whereas $foo does not, and the object destruction behaves differently… I don’t know.

Lastly, even after explicitly calling $foo->__destruct() (even when it had “unset($this);” inside it), the reference to the $foo object remained visible. I had to still explicitly call unset($foo) to get rid of it.

So, my advice based on the behavior I saw in my experiments:
– always unset($bar) your class’s component objects from inside that class’s __destruct() method; no explicit component destructor calls seem to be required other than those unsets, though.
– always explicitly call $foo->__destruct() in your code that _uses_ your class
– always explicitly follow $foo->__destruct() with unset($foo).

This seems to be the best cleanup approach to take. Just for my own sanity, I also will always keep an unset($this) at the end of each __destruct() method.
nerdystudmuffin at gmail dot com
09-Jan-2008 11:11
Correction to the previous poster about non public constructors. If I wanted to implement Singleton design pattern where I would only want one instance of the class I would want to prevent instantiation of the class from outside of the class by making the constructor private. An example follows:

class Foo {

private static $instance;

private __construct() {
// Do stuff
}

public static getInstance() {

if (!isset(self::$instance)) {
$c = __CLASS__;
$instance = new $c;
}

return self::$instance;
}

public function sayHello() {
echo “Hello World!!”;
}

}

$bar = Foo::getInstance();

// Prints ‘Hello World’ on the screen.
$bar -> sayHello();
david at synatree dot com
29-Dec-2007 01:26
When a script is in the process of die()ing, you can’t count on the order in which __destruct() will be called.

For a script I have been working on, I wanted to do transparent low-level encryption of any outgoing data. To accomplish this, I used a global singleton class configured like this:

class EncryptedComms
{
private $C;
private $objs = array();
private static $_me;

public static function destroyAfter(&$obj)
{
self::getInstance()->objs[] =& $obj;
/*
Hopefully by forcing a reference to another object to exist
inside this class, the referenced object will need to be destroyed
before garbage collection can occur on this object. This will force
this object’s destruct method to be fired AFTER the destructors of
all the objects referenced here.
*/
}
public function __construct($key)
{
$this->C = new SimpleCrypt($key);
ob_start(array($this,’getBuffer’));
}
public static function &getInstance($key=NULL)
{
if(!self::$_me && $key)
self::$_me = new EncryptedComms($key);
else
return self::$_me;
}

public function __destruct()
{
ob_end_flush();
}

public function getBuffer($str)
{
return $this->C->encrypt($str);
}

}

In this example, I tried to register other objects to always be destroyed just before this object. Like this:

class A
{

public function __construct()
{
EncryptedComms::destroyAfter($this);
}
}

One would think that the references to the objects contained in the singleton would be destroyed first, but this is not the case. In fact, this won’t work even if you reverse the paradigm and store a reference to EncryptedComms in every object you’d like to be destroyed before it.

In short, when a script die()s, there doesn’t seem to be any way to predict the order in which the destructors will fire.
Typer85 at gmail dot com
21-Dec-2007 09:33
I mentioned in my post below this one that the solution is not perfect and has some flaws.

Because my note was too big and was not allowed to be submitted, I had to write a new note here containing the flaws. If an editor sees this, please combine both notes to allow for easier reading.

– This solution assumes that Class B and Class C extend or build upon Class AAbstract. If Class B or Class C extend from each other or from Class A, the original problem will be encountered again.

– There will be extra overhead in including an extra file … the dummy Class AAbstract.
Typer85 at gmail dot com
21-Dec-2007 09:31
In regards to a Class Constructor visibility …

I too was having the same problem with Class Constructor visibility, in which I had one Class that was extended by several other Classes. The problem that I encountered was in one of the Child Classes, I wanted a weaker visibility. Consider the following example:

class A {

// Public Constructor …
// No Problems Here.

public function __construct( ) {

}

// Class Function.

public function functionA( ) {

}
}

class B extends A {

// Public Constructor …
// Same As Parent Class …
// Again No Problems Here.

public function __construct( ) {

}

// Class Function.

public function functionB( ) {

}
}

class C extends A {

// Private Constructor …
// Weaker Then Parent Class …
// PHP Will Throw A Fatal Error.

private function __construct( ) {

}

// Class Function.

public function functionC( ) {

}
}

?>

Nothing new in the above example that we have not seen before. My solution to solve this problem?

Create an Abstract Class with all the functionality of Class A. Make its Class Constructor have a visibility of Protected, then extend each of the three Classes above from that Abstract Class. In a way, the Abstract Class acts as a dummy Class to get rid of the visibility problem:

abstract class AAbstract {

// Protected Constructor …
// Abstract Class Can Not Be Created Anyway …
// No Problems Here.

protected function __construct( ) {

}

// Class Function …
// Originally In Class A …
// Which Was Used As A Super Class.

public function functionA( ) {

}
}

class A extends AAbstract {

// Public Constructor …
// Stronger Than Parent Class …
// Again No Problems Here.

public function __construct( ) {

// By Moving All The Functionality Of
// Class A To Class AAbstract Class A
// Will Automatically Inherit All Of
// Its Functionality. The Only Thing
// Left To Do Is To Create A Constructor
// Which Calls Class AABstract’s Constructor
// To Mimic Similar Behavior.

parent::__construct( );
}

// No Need To Redeclare functionA( )
// Since It Was Moved To Class
// AAbstract.
}

class B extends AAbstract {

// Public Constructor …
// Stronger Than Parent Class …
// Again No Problems Here.

public function __construct( ) {

parent::__construct( );
}

// Class Function …
// Specific To This Class.

public function functionB( ) {

}
}

class C extends AAbstract {

// Protected Constructor …
// Same As Parent Class …
// Again No Problems Here.

protected function __construct( ) {

}

// Class Function …
// Specific To This Class.

public function functionC( ) {

}
}

?>

As you can see the problem is more or less fixed. Class AAbstract acts a dummy class, containing all the original functionality of Class A. But because it has a protected Constructor, in order to make its functionality available, Class A is redeclared as Child Class with the only difference of it having a public Constructor that automatically calls the Parent Constructor.

Notice that Class B does not extend from Class A but also from Class AAbstract! If I wanted to change Class B’s Constructor to protected, I can easily do it! Notice that an extra Method was added to Class B … this is because Class B has extra functionality specific to itself. Same applies to Class C.

Why don’t Class B and Class C extend from Class A? Because Class A has a public Constructor, which pretty much defies the point of this solution.

This solution is not perfect however and has some flaws.

Good Luck,
randallgirard at hotmail dot com
26-Oct-2007 10:17
I’ve been working on a project for a while now, and for example in my DB handler I wanted to load var’s to the objects late; However, without doing it manually on the object itself but through a single static call. For other reasons, in my Sessions I then wanted to end them early without registering a shutdown routine for every possible session. Hence, I needed a way to track EVERY instance or object of the class.

(Of course in a normal website design, this would be overly coded. It’s more of a framework for a CMS, Daemon service, anything I wanna create etc…)

class example {

public static $OBJS = array();
public $id;

public function __construct() {
example::$OBJS[] = $this;
# I actually use a ‘lastKey’ routine here, but in this example the following should work:
$this->id = key( array_slice(example::$OBJS, count(example::$OBJS) -1, 1, true) );
}

public function __destruct() {
$this->close();
}

# unset the tracked object
private function destruct() {
if ( isset(example::$OBJS[$this->id]) )
unset(example::$OBJS[$this->id]);
}

# public shutdown routine
public function close() {
if ( isset($this->destructed) )
return;
# …
$this->destruct();
$this->destructed = true;
}

}

?>

You could then also use register_shutdown_function(…) to call a static class method, which loops through ALL the objects and calls the $obj->close routine.

# register a shutdown function which triggers before destructors (hence when such results are desired for a Session class, etc)
register_shutdown_function(“example::destructors”);

class example {

# … see above code example

# static class method to destruct all objects
public static function destructors() {
foreach ( example::$OBJS as $obj )
$obj->destruct();
}

}

This will probably give some people new ideas, and other will probably be confused. Happy coding…

NOTE: I didn’t test the code(s) above. They were a rewritten example from my frameworks.

?>
James Laver
25-Oct-2007 02:45
I recently found, while implementing a database backed session class, that PHP has an apparently less than desirably structured destruction order. Basically, my session class which would have saved when destructed, was being destructed after one of the classes it depends on. Apparently we cannot, therefore depend on PHP to use reverse initialisation order.

My solution was to use register_shutdown_function, which is called before any objects are killed on script end.

Quick example (if you’re going to use it, I recommend tidying up the code somewhat) :
class Session
function __construct()
{
//Initialise the session here…

//Register the shutdown function
register_shutdown_function(array($this,”save”));
}

function save()
{
//Save it here
}

function __destruct()
{
//Persisting the session here will not work.
}
?>
magus do t xion a t g mail d ot c o m
11-Oct-2007 12:20
Looking through the notes I noticed a few people expressing concern that PHP5 does not support multiple constructors…

Here is an example of a method that I use which seems to work fine:

class Example
{
function __construct()
{
echo “do some basic stuff here”;
}

function Example($arg)
{
echo $arg;
}
}

You then can call with or without arguments without having notices and/or warnings thrown at you… Of course this is limited but if you don’t need something complex this can help to get the job done in some situations. I believe you could also add arguments to the __construct() function and as long as it is different than Example() ‘s args you would be fine. Although I have yet to test this.
prieler at abm dot at
27-Jul-2007 12:42
i have written a quick example about the order of destructors and shutdown functions in php 5.2.1:

class destruction {
var $name;

function destruction($name) {
$this->name = $name;
register_shutdown_function(array(&$this, “shutdown”));
}

function shutdown() {
echo ‘shutdown: ‘.$this->name.”\n”;
}

function __destruct() {
echo ‘destruct: ‘.$this->name.”\n”;
}
}

$a = new destruction(‘a: global 1’);

function test() {
$b = new destruction(‘b: func 1’);
$c = new destruction(‘c: func 2’);
}
test();

$d = new destruction(‘d: global 2’);

?>

this will output:
shutdown: a: global 1
shutdown: b: func 1
shutdown: c: func 2
shutdown: d: global 2
destruct: b: func 1
destruct: c: func 2
destruct: d: global 2
destruct: a: global 1

conclusions:
destructors are always called on script end.
destructors are called in order of their “context”: first functions, then global objects
objects in function context are deleted in order as they are set (older objects first).
objects in global context are deleted in reverse order (older objects last)

shutdown functions are called before the destructors.
shutdown functions are called in there “register” order. 😉

regards, J
fredrik at rambris dot com
16-Jul-2007 06:59
The fact that class names are case-insensitive in PHP5 also applies to constructors. Make sure you don’t have any functions named like the class *at all*.

This has bitten me a few times.

class Example extends Base
{
function example()
{
echo “This gets called”;
}
}

class Base
{
function __construct()
{
echo “Not this”;
}
}

?>
theubaz at gmail dot com
11-Jul-2007 04:35
What you could do is write the constructor without any declared arguments, then iterate through the arguments given and check their types/values to determine what other function to use as the constructor.
soapthgr8 at gmail dot com
06-Jul-2007 07:46
This is just to clarify that the Singleton pattern is a bit more complex than just making the constructor private. It also involves caching an instance of the object and always returning the cached value. So, in the previous example, the getNewInstance() function would undermine the intent of the Singleton pattern. Instead you would just need a getInstance() function, like so.

class A {
// cached instance
private static oInst = null;

/**
* Prevent an object from being constructed.
*/
private function __construct( ) {}
/**
* Function to return the instance of this class.
*/
public static function getInstance( ) {
if (is_null(self::$oInst)) {
self::$oInst = new A( );
}
return self::$oInst;
}
}
?>
Typer85 at gmail dot com
03-Jun-2007 07:16
I am not sure if the following is known or not, but here goes.

I am sure most are aware of the concept of making a Class Constructor private to prevent an Object of that Class from being created as follows:

class A
{
/**
* Prevent An Object From Being Constructed.
*/
private function __construct( ) {

}
}

?>

In some code, if I try to do the following:

$Obj = new A( );

?>

PHP will fail with a fatal error. This is useful when creating Classes that are composed of only static functions or in a more advanced example, when applying the Singleton Pattern to a Class design.

However what is not properly documented in this manual but is pretty simple to note, especially if you read the notes regarding the Singleton Pattern, is that you can create an Object of a Class that has a private Constructor from within the Class itself.

Confused … so am I, so allow me to provide a visual example as follows:

class A
{
/**
* Prevent An Object From Being Constructed.
*/
private function __construct( ) {

}
/**
* Function To Return An Instance Of This Class.
*/
public static function getNewInstance( ) {

return new A( );
}
}

?>

In some code, if I try to do the following:

$Obj = A::getNewInstance( );

?>

PHP in this case will not fail with a fatal error and instead the variable ‘$Obj’ becomes an Object with an instance of Class ‘A’.

This is a simple example and pretty advanced things can be done using this method. I am sure advanced developers are aware of this so this is just a little note going out to new PHP developers.
Peter Molnar
17-May-2007 08:32
The manual says: “Destructor is called during the script shutdown so headers are always already sent.”

This is obviously not true. If you instantiate a class in a function or class method, but it is not returned by the method, nor is it saved in a global or object member variable, the object is cleaned up, and it’s destructor is called. This can of course occur before anything is printed or sent to the client.
frederic dot barboteu at laposte dot net
14-Apr-2007 07:11
The manual says:
“Like constructors, parent destructors will not be called implicitly by the engine.”

This is true ONLY when a __destruct() function has been defined by the child class.
If no __destruct() function exists in the child class, the parent’s one will be implicitly executed.

So be carefull if you have some ancestor executing a particular task in its __destruct() function, an you plan its childs to execute it or not, wether you include “parent::__destruct()” or not.
If you want the child not to execute its parent __destruct() function, you must ensure that it has its own __destruct() function, even if empty. Then the parent’s one will not be executed.

This can be verified with the following code:
#
class AncestorClass {
function __destruct() {
echo ‘
AncestorClass: destructing ‘.get_class($this);
}
}
#
class ParentDestructClass extends AncestorClass {
function __destruct() {
echo ‘ParentDestructClass: destructing itself’;
parent::__destruct();
}
}
#
class EmptyDestructClass extends AncestorClass {
function __destruct() {
echo ‘EmptyDestructClass: destructing itself’;
}
}
#
class NoDestructClass extends AncestorClass {
}
#—
echo ‘


‘;
$p=new ParentDestructClass();
unset($p);
echo ‘


‘;
$e=new EmptyDestructClass();
unset($e);
echo ‘


‘;
$n=new NoDestructClass();
unset($n);
echo ‘


‘;
?>
which displays:

ParentDestructClass: destructing itself
AncestorClass: destructing ParentDestructClass

EmptyDestructClass: destructing itself

AncestorClass: destructing NoDestructClass

robert at lax-berlin dot de
12-Nov-2006 12:48
In response to prauscher at gmx dot net:

As tcknetwork wrote earlier, if you try to access a file from a destructor, you have to be aware that you are probably in the webservers root directory, because the destructor already “forgot” what you working directory was. If you try to write a file there, you will probably have no permission to do so.
Read tcknetwork’s post for a solution.
maniac_warlord at web dot de
04-Nov-2006 04:50
as reported in bug 34206 the working dir is changed to the server root
the best workaround is
class Foo
{
public function bar()
{
$this->_cwd = getcwd();
}

public function __destruct()
{
chdir($this->_cwd);
}
}
?>
Be aware the booty trap!
http://bugs.php.net/bug.php?id=34206
phaxius
01-Nov-2006 09:23
Hello, I’ve been messing with php for about a week but am learning a lot. It occurred to me that it might be necessary in some cases to write a class that takes a variable number of arguments. After some experimentation, this example was formed:

class variableArgs{
public $a = array();
protected $numOfArgs;
public function __construct()
{
$numOfArgs=func_num_args();
if(func_num_args()==0)
{
$numOfArgs=1;
$a[0]=’No arguments passed’;
$this->Arg[0]=$a[0];
}
else
for($i=0; $i {
$a[$i]=func_get_arg($i);
$this->Arg[$i]=$a[$i];
}
}
public function showArgs()
{
echo ‘showArgs() called
‘;
for ($i=0; $i<$numOfArgs; $i++)
{
echo ‘$i: ‘ . $i . ‘
‘;
echo $this->Arg[$i];
echo ‘
‘;
}
}
public function __destruct(){}

}

$test1 = new variableArgs;
$test2 = new variableArgs(“arg1”);
$test3 = new variableArgs(“arg1”, “arg2”);
$test4 = new variableArgs(“arg1”, “arg2”, “arg3”);

$test1->showArgs();
$test2->showArgs();
$test3->showArgs();
$test4->showArgs();

This outputs the following:

showArgs() called
$i: 0
No arguments passed
showArgs() called
$i: 0
arg1
showArgs() called
$i: 0
arg1
$i: 1
arg2
showArgs() called
$i: 0
arg1
$i: 1
arg2
$i: 2
arg3

I have no idea how efficient this is, but it works at any rate. Hopefully this helps someone.
01-Oct-2006 11:03
This is a simple thing to bear in mind but it’s also easy to forget it. When chaining object constructors and destructors, always remember to call the superclass __construct() method in the subclass __construct() so that all superclass members are properly initialized before you start initializing the ones belonging to your subclass.

Also, you will usually want to do your own cleanup first in your subclass __destruct() method so you will probably want to call the superclass __destruct() as the last thing in your subclass so that you can use resources defined in the superclass during the cleanup phase.

For example, if your superclass includes a database connection and your subclass __destruct method commits things to the database then if you call the superclass destruct before doing so then the database connection will no longer be valid and you will be unable to commit your changes.
chanibal at deltasoft dot int dot pl dot SPAMPROTECT
20-Aug-2006 09:56
Note that if a class contains another class, the contained class’s destructor will be triggered after the destructor of the containing class.

class contained {

protected $parent;

public function __construct(&$p) {
# $this->parent=&$p;
}

public function __destruct() {
/* unset $this->parent */
print ‘contained ‘;
}
}

class containing {

protected $contained;

public function __construct() {
$this->contained=new contained($this);
}

public function __destruct() {
// unset($this->contained);
print ‘containing ‘;
}
}

new containing();
?>

Will output
containing contained

After uncommenting the // comment, the output will change to
contained containing

Adding a reference from the contained class to the containing one (the # comment) will not change that, but beware, because it can cause random errors in other destructors in the parts of the script which seem unrelated! (PHP Version 5.1.2)
prauscher at gmx dot net
14-Aug-2006 04:05
I saw no note in the manual about my function. If you want to write a file in a __destruct – function, it will fail with a “Permission denied” Error.
Reza Mahjourian
10-Jul-2006 02:18
Peter has suggested using static methods to compensate for unavailability of multiple constructors in PHP. This works fine for most purposes, but if you have a class hierarchy and want to delegate parts of initialization to the parent class, you can no longer use this scheme. It is because unlike constructors, in a static method you need to do the instantiation yourself. So if you call the parent static method, you will get an object of parent type which you can’t continue to initialize with derived class fields.

Imagine you have an Employee class and a derived HourlyEmployee class and you want to be able to construct these objects out of some XML input too.

class Employee {
public function __construct($inName) {
$this->name = $inName;
}

public static function constructFromDom($inDom)
{
$name = $inDom->name;
return new Employee($name);
}

private $name;
}

class HourlyEmployee extends Employee {
public function __construct($inName, $inHourlyRate) {
parent::__construct($inName);
$this->hourlyRate = $inHourlyRate;
}

public static function constructFromDom($inDom)
{
// can’t call parent::constructFromDom($inDom)
// need to do all the work here again
$name = $inDom->name; // increased coupling
$hourlyRate = $inDom->hourlyrate;
return new EmployeeHourly($name, $hourlyRate);
}

private $hourlyRate;
}
?>

The only solution is to merge the two constructors in one by adding an optional $inDom parameter to every constructor.
Peter Molnar
18-May-2006 06:24
There were many notes about the inability of defining multiple constructors for the class.

My solution is to define separate static methods for each type of constructor.
class Vector {
private $x;
private $y;

public function __construct() {
$this->x = 0;
$this->y = 0;
}

public static function createXY($x, $y) {
$v = new Vector();
$v->x = $x;
$v->y = $y;
return $v;
}
}
?>
ckoschmied at web dot de
07-Apr-2006 07:58
Be aware of the fact that if you create a new instance of a class like this:

$instance = new Class();

$instance will not contain a valid reference to the newly created object until the constructor is finished. So don’t use $instance while the constructor is still running.

Well, on the other side, why would you want to do it? I wanted to, and it took me some hours to figure out.
Even though it’s quite obvious if you think about it 🙂
jcaplan at bogus dot amazon dot com
24-Mar-2006 09:52
__construct and __destruct must be declared public in any class that you intend to instantiate with new. However, in an abstract (or never-instantiated base) class you can declare them private or protected, and subclasses can still refer to them via parent::__construct (!) (tested in PHP 5.1.2).
09-Feb-2006 10:55
(Refering to: caliban at darklock dot com)

To force a constructor always to be called, and still be able to define a constructor on a derived class use the model below. Ideal for module architectures, because you only have to know the file and classname to construct an object.

class Parameter {}

abstract class BaseClass
{
protected $param;

public final function __construct( Parameter $param )
{
$this->param = $param;
$this->pseudoConstruct();
}

protected abstract function pseudoConstruct();
}

class ConcreteClass extends BaseClass
{
protected function pseudoConstruct()
{
echo __CLASS__.’ constructor’;
}
}

$refl = new ReflectionClass( ‘ConcreteClass’ );
if( !$refl->isSubclassOf( ‘BaseClass’ ) ) throw new Exception( ‘Invalid base class!’ );
$refl->newInstance( new Parameter() );
?>
jochem AT mondrian-it d_o_t nl
30-Jan-2006 04:07
at: derk AT oneindig DOT com

You can achieve identical functionality by doing this:
class Parent {
function __construct()
{
echo “Parent constructor called\\n”;
}
}

class Child extends Parent {
function __construct()
{
parent::__construct();
echo ” Child ‘contructor’ called”;
}
}

$c = new Child();
?>
Added advantage is that Parent doesn’t need to have the method myConstruct(), and that you’re using constructors like they were intended.
developit at mail dot ru
25-Jan-2006 02:32
as [kida at keymail dot it] said you can’t weaken a visibility of constructor when extending some class. but suggested trick that uses both old and new constructor namimg syntaxes to weaken visibility from ‘protected’ to ‘public’ seems a little bit odd. allthough it works allright. declaring extended class as ‘abstract’ with ‘public’ constructor will do quite the same thing in a more elegant manner and without any syntax mess.

class A
{
public function __construct()
{
//do smth
}
}

abstract class B extends A
{
public function __construct()
{
parent::__construct();
}
}
?>

thus, you avoid instanciating class B as if it had a protected contructor
aya at eh dot org
01-Dec-2005 02:20
For those who aren’t already aware, PHP5 currently suffers from the classic reference counting leak. See http://en.wikipedia.org/wiki/Reference_counting for more info.

Example code:

class Noisy
{
private $name;

public function __construct($name)
{
$this->name = $name;
echo “Noisy::__construct($this->name)\n”;
}

public function __destruct()
{
echo “Noisy::__destruct($this->name)\n”;
}
}

function foo($num)
{
$noisy = new Noisy($num);
//$noisy->me = $noisy; // Uncomment this line to create a cyclic reference
}

for ($i = 0; $i < 10; ++$i)
foo($i);

?>

As it stands, the destructor of class ‘Noisy’ will be called on ‘$noisy’ when it goes out of scope in function ‘foo’, but uncommenting the second line in function ‘foo’ will prevent this, and cause a memory leak.

See http://bugs.php.net/bug.php?id=33595 for a bug report, which reads as if this is not likely to get fixed in the near future, so watch out!
derk AT oneindig DOT com
03-Nov-2005 02:02
If a constructor is not present in a child class, php5 will try to call a constructor from the parent class. This behaviour can be used to somewhat simulate constructor chaining.

abstract class Parent {
function __construct()
{
echo “Parent constructor called\n”;
$this->myConstruct();
}
}

class Child extends Parent {
function myConstruct()
{
echo ” Child ‘contructor’ called”;
}
}

$c = new Child();
?>

will output:
Parent constructor called
Child ‘constructor’ called
contact at tcknetwork dot com
21-Sep-2005 12:54
be careful while trying to access files with __destruct() because the base directory (getcwd()) will be the root of your server and not the path of your script, so add before all your path called in __destruct() :
EITHER dirname($_SERVER[“SCRIPT_FILENAME”]).”my/path/”
OR dirname(__FILE__).”my/path/”
(be careful with includes, it will give the path of the file processed and not the main file)
php dot net at lk2 dot de
13-Aug-2005 09:50
It looks like `echo()`ed output from the __destructor() function is displayed onto screen _before_ other output that the class may have have already sent before.

This can be misleading if you have debug info printed in the destructor but not a problem if you know it.
stanley dot turnteen at gmail dot com
05-Aug-2005 12:43
IMHO using func_get_args() is superior to constructor polymorphism, because you don’t have to define constructors for every possible way a class can be initialized.

The pattern I use looks like this; all you have to do is pass the parameters in the correct order.

class Movie
{
public $title;
public $director;
public $stars;
public $year_released;

public function __construct()
{
$args = func_get_args();

foreach(array(“title”, “director”, “stars”, “year_released”) as $i)
{
if(empty($args))
{
break;
}

$this->$i = array_shift($args);
}
}

}
?>
dominics at gmail dot com
10-Jul-2005 07:12
If you’re using E_STRICT error reporting, PHP will tell you if you define both __construct() and an old-style constructor (a function with the same name as the class) together in a class. Note that this occurs even if the old constructor function is abstract or final (for instance, if you were intending to only use it in a sub-class). Be wary of this if you’re trying to implement the ‘command’ design pattern.

The solution? Either turn E_STRICT off (and possibly forgo some other important notices), rename your function (and possibly make things a little more complicated), or look at using an interface.
rocco at bluora dot com dot au
16-Apr-2005 08:29
Before PHP reaches the point where it calls the __destruct functions, it has already done a session_write_close() so you can no longer write anything to the session.

I wanted it to copy some variables from my class into the session once the script had finished but now having to get the last function to call a SaveToSession() function.

In php versions 5.0.2 and 5.0.4
contact at tcknetwork dot com
15-Apr-2005 08:45
Note that php5 use in priority __construct() instead of [classname](). So you could build a constructed/destructed class for php4/5 very easily using this.
class test {
function test() {
$this->__construct();
register_shutdown_function(array($this,”__destruct”));
}
function __construct() {
echo “construct\n”;
}
function __destruct() {
echo “destruct\n”;
}
};
$t=new test();
?>
In case you use unset($t) in php4, the destructor is not called. so be careful.
apfelsaft
30-Mar-2005 01:59
at the end of a script all remaining objects aren’t in fact destructed. it is only their __destruct() method, which will be called. the objects still exist after that.

so, if your database connection object has no __destruct() or at least it doesn’t disconnects the database, it will still work.

in general, there is no need to disconnect the database (especially for persistent connections).
04-Mar-2005 03:48
> To caliban at darklock dot com: Why not just define
> a dummy constructor

Because you don’t always get to modify your base classes. Once you get beyond the “build to suit” range of software development, you end up having to work with other people’s code, and sometimes you just plain can’t change it. When Bob is in charge of making changes to that object, you can’t add a dummy constructor. You have to tell Bob to do it, and until Bob does it, you don’t get it. So if you want to hit your deadlines, you don’t count on Bob caring enough about your job to make the changes you want… you work around it. It might be convenient for *you* to have a constructor on that object, but when you’re only one of several thousand people that are using it, your convenience isn’t generally among the design criteria.

Smaller projects where you can add whatever you want wherever you want will not have this problem, in which case the dummy constructor is indeed a better solution.
24-Feb-2005 01:08
To caliban at darklock dot com: Why not just define a dummy constructor in the base class? This adds little overhead, and allows you to both extend the class worry-free and later add construct functionality to the base class.

And now, about destructors: I haven’t seen this clarified anywhere in the manual, but object destructors are called implicitly at script shutdown for all objects that still exist at that Tpoint. his happens *after* any shutdown functions set with have been called.

Objects appear to be destructed in the order they were defined, which means you have to be careful with destruct methods that rely on the functionality of other objects (e.g. on a database-handler) as they will have shut down already.