0%

先来讲解,为什么会产生粘包问题呢,网上炒了一段,如果想要仔细了解的同学可以去搜寻一下对应的资料

  • 当应用层协议使用 TCP 协议传输数据时,TCP 协议可能会将应用层发送的数据分成多个包依次发送,而数据的接收方收到的数据段可能有多个『应用层数据包』组成,所以当应用层从 TCP 缓冲区中读取数据时发现粘连的数据包时,需要对收到的数据进行拆分。

1.话不多说上代码,服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//创建Server对象,监听 127.0.0.1:9501 端口
$server = new Swoole\Server('127.0.0.1', 9501);
$server->set([
'open_length_check' => true,//打开包检测
'package_max_length' => 1 * 1024 * 1024, //1兆
'package_length_type' => 'n', //小n 2个字节,大N 4个字节
'package_length_offset' => 0,//包头从第几位开始截取
'package_body_offset' => 2,//包头到几位结束
]);


//监听连接进入事件
$server->on('Connect', function ($server, $fd) {
echo "Client: Connect.\n";
});

//监听数据接收事件
$server->on('Receive', function ($server, $fd, $from_id, $data) {
echo '接收到数据:'.$data.PHP_EOL;
$server->send($fd, "Server: " . $data);
});

//监听连接关闭事件
$server->on('Close', function ($server, $fd) {
echo "Client: Close.\n";
});

//启动服务器
$server->start();

2.客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

$client = new Swoole\Client(SWOOLE_SOCK_TCP );

if (!$client->connect('127.0.0.1', 9501, -1)) {
exit("connect failed. Error: {$client->errCode}\n");
}

//粘包
for($i=0; $i<10; $i++){
$str = 'hello';//要发送的内容
$len = pack('n',strlen($str));//把长度转换二进制,n表示2个字节长度
$send = $len.$str;//拼接
var_dump($send);
$client->send($send);//发送

}

$client->recv();

3.执行效果(服务端)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost 03]# php xintiao_tcp_server.php 
Client: Connect.
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
接收到数据:hello
Client: Close.

3.执行效果(客户端)

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost 03]# php xintiao_tcp_client.php 
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"
string(7) "hello"

服务端设计心跳包的目的,网上炒了一段,如果想要仔细了解的同学可以去搜寻一下对应的资料

  • 探知对端应用是否存活,服务端客户端都可以发心跳包,一般都是客户端发送心跳包,服务端用于判断客户端是否在线,从而对服务端内存缓存数据进行清理(玩家下线等);问题在于,通过TCP四次握手断开的设定,我们也是可以通过Socket的read方法来判断TCP连接是否断开,从而做出相应的清理内存动作

1.话不多说上代码,服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//创建Server对象,监听 127.0.0.1:9501 端口
$server = new Swoole\Server('127.0.0.1', 9501);

$server->set([
'heartbeat_idle_time' => 3, // 表示一个连接如果3秒内未向服务器发送任何数据,此连接将被强制关闭
'heartbeat_check_interval' => 2, // 表示每2秒遍历一次
]);


//监听连接进入事件
$server->on('Connect', function ($server, $fd) {
echo "Client: Connect.\n";
});

//监听数据接收事件
$server->on('Receive', function ($server, $fd, $from_id, $data) {
$server->send($fd, "Server: " . $data);
});

//监听连接关闭事件
$server->on('Close', function ($server, $fd) {
echo "Client: Close.\n";
});

//启动服务器
$server->start();

2.客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//new对象
$client = new Swoole\Client(SWOOLE_SOCK_TCP );
//建立tcp连接
if (!$client->connect('127.0.0.1', 9501, -1)) {
exit("connect failed. Error: {$client->errCode}\n");
}

//定时器每4千毫秒执行一次
swoole_timer_tick(4000, function ($timer_id) use ($client) {
echo "string\n";
//发送消息
$client->send(1);
//接收消息
$client->recv();
});

  • 注意使用sleep()函数会影响定时器的执行,因为sleep函数会阻碍整个php程序的进程

  • 最近在学swoole 的websocket,来做一个小案例聊天软件

1.先来搭建一个服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

//创建WebSocket Server对象,监听0.0.0.0:9502端口,这个ip得注意一下,很多新手不懂这个0.0.0.0,跟你直接绑定127.0.0.1,的区别,如果你直接写127.0.0.1的话,你用内网ip访问本机地址是访问不到的,0.0.0.0,是不限制ip,127.0.0.1,是限制只能用127.0.0.1来访问注意这一点
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9502);

//监听WebSocket连接打开事件
$ws->on('open', function ($ws, $request) {

//把自己的id返回回去
$redata = [
'fd'=>$request->fd
];

$ws->push($request->fd,json_encode($redata));
});

//监听WebSocket消息事件
$ws->on('message', function ($ws, $frame) {
//解析json
$data = json_decode($frame->data,true);
//拼接要发送的数据
$redata = [
'wfid'=>$frame->fd,
'conent'=>$data['conent']
];
//发送
$ws->push($data['fid'],json_encode($redata));
});

//监听WebSocket连接关闭事件
$ws->on('close', function ($ws, $fd) {
echo "{$fd} 关闭连接";
});

$ws->start();

1.在来写个html来测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websoket聊天</title>
</head>
<body>
<div id="messages">
</div>
<div>
<div>对方fdid <input id="fid" name='fid' type="text"></div>
<div>发送内容 <input id="conent" name='conent' type="text"></div>
<button id="send">发送</button>
</div>
</body>
  <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>


// 打开一个 web socket
var ws = new WebSocket("ws://192.168.80.131:9502");
ws.onopen = function()
{
//刚链接发送
};

ws.onmessage = function (evt)
{
var received_msg = evt.data;
console.log(received_msg);
data = JSON.parse(received_msg);
//是否第一次链接
if(data.fd){
conent = "你的fdid为:"+data.fd;
}else{
conent = "<div>对方fid:" + data.wfid + "说:" + data.conent +"</div>";

}

$("#messages").append(conent);

};

ws.onclose = function()
{
// 关闭 websocket
alert("连接已关闭...");
};

$("#send").click(function(){
//获取要发送的fd
fid = $("#fid").val();
//获取要发送的值
conent = $("#conent").val();
console.log(conent);
//追加本地页面
$("#messages").append("<div>我说:" + conent +"</div>");
var json ={"fid":fid, "conent":conent};
//json转换字符串发送
var jsonstr =JSON.stringify(json);
//发送
ws.send(jsonstr);
})

</script>
</html>


3.见证奇迹的时候到了

  • 启动 服务端
    1
    2
    [root@localhost 02_chagn]# php websoket_server.php 

  • 打开两个页面,当打开过后,出现两个fd
1
2
3
[root@localhost 02_chagn]# php websoket_server.php 
int(1)
int(2)
  • 页面1效果

页面1

  • 页面2效果

页面2

1.找到nginx配置文件nginx.conf,location里面添加

1
2
3
4
5
6
7
8
9
server {
.....
location / {
proxy_pass http://127.0.0.1:8081/;
index index.php index.html;

}
....
}

proxy_pass 后面是你服务器的ip,需要反向代理的ip地址

1.找到nginx配置文件nginx.conf,在http里面添加

1
2
3
4
5
6
7
8
9
http {
......
upstream group{
server 154.12.0.11:80 ;
server 47.75.201.23:80 ;
}

......
}

server 后面是你服务器的ip,需要负载均衡的IP地址

2.然后在service里面location下面添加

1
2
3
4
5
6
7
8
9
server {
.....
location / {
proxy_pass http://group/;
index index.php index.html;

}
....
}

proxy_pass 这里设置的http://group/ ,这个group怎么来的就是上面第一步设置upstream 后面跟着的这个参数

3.配置权重问题

第一个就是默认配置,默认配置的话,他们负载均衡的方式就是随机选择服务器来访问

第二个weight,这种就是权重方式,把他设置的越高,重复的次数就越高,配置如下

1
2
3
4
5
6
7
8
9
http {
......
upstream group{
server 154.12.0.11:80 weight=1;
server 47.75.201.23:80 weight=1;
}

......
}

第三个ip_hash,是把每个请求按访问ip的hash结果分配,这样每个访客固定访问一个服务器,可以解决负载均衡session的问题,配置如下

1
2
3
4
5
6
7
8
9
http {
......
upstream group{
ip_hash;
server 154.12.0.11:80 ;
server 47.75.201.23:80 ;
}
......
}

第四个fair,按照服务器的响应时间来分配请求,响应时间段的优先分配,配置如下

http {
  ......
    upstream group{
        server 154.12.0.11:80 weight=1;
        server 47.75.201.23:80 weight=1;
    fair;
    }
  ......
}

需要两个服务器或者两个虚拟机都可以,一个是主数据库一个是从数据

1.第一步需要主服务器修改 /etc/my.conf

1
2
3
4
5
6
7
8
9
10
11
#日志名称
log_bin=master-a-bin

#日志文件格式
binlog-format = Row

#服务器id
server-id=1

#主从复制的库
binlog_do_db=tea

2.修改完需要给重服务器授权(在主服务器的mysql里面执行下面这段代码授权)

1
grant replication slave on *.* to '主服务器mysql账号'@'从服务器地址' identified by '主服务器mysql账号';

当我修改的时候提示了报修改密码错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Your password does not satisfy the current policy requirements

mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | OFF |
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+--------------------------------------+--------+
7 rows in set (0.01 sec)

经过查看是mysql的密码规则用简单的密码不行,提供一下解决方案(如果上面修改没有报错请忽略这一步)

mysql 5.7解决方案

1
2
set global validate_password_policy=0;
set global validate_password_length=1;

mysql 8.0解决方案

1
2
set global validate_password.policy=0;
set global validate_password.length=1;

再次执行,就成功了

1
2
mysql> grant replication slave on *.* to 'robert'@'2.56.184.38' identified by 'robert&tea321';
Query OK, 0 rows affected, 1 warning (0.00 sec)

3.现在来修改从服务器的mysql

1
2
3
4
5
6
7
8
9
10
11
修改mysql配置文件
vim /etc/my.cnf

#日志名称
log_bin=master-a-bin

#日志文件格式
binlog-format = Row

#服务器id(必须唯一,主服务器是1,这个id不能重复)
server-id=2

重启两个mysql

1
service mysqld restart

4.验证是否设置成功

主服务器mysql

1
2
3
4
5
6
7
mysql> show master status;
+---------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------+----------+--------------+------------------+-------------------+
| master-a-bin.000001 | 4635 | tea | | |
+---------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

解释一下上面这几个字段什么意思,这几个字段下面用得到的
file 生成的日志文件名
position 文件名所在的位置简称偏移量
Binlog_Do_DB 需要实现主重复制的数据库

5.设置从服务器找到主服务器

1
2
mysql> change master to master_host='主服务器ip地址', master_user='root', master_password='root', master_port=3306, master_log_file='master-a-bin.000001', master_log_pos= 4635, master_connect_retry=30;
Query OK, 0 rows affected, 2 warnings (0.03 sec)

解释一下上面几个参数的意思
master_host :Master的地址
master_port:Master的端口号
master_user:用于数据同步的用户
master_password:用于同步的用户的密码
master_log_file:指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值
master_log_pos:从哪个 Position 开始读,即上文中提到的 Position 字段的值
master_connect_retry:如果连接失败,重试的时间间隔,单位是秒,默认是60秒

6.启动slave的数据同步

1
2
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

停止同步命令
stop slave;

查看slave配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 154.17.0.136
Master_User: robert
Master_Port: 3306
Connect_Retry: 30
Master_Log_File: master-a-bin.000001
Read_Master_Log_Pos: 4635
Relay_Log_File: mysqld-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: master-a-bin.000001
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 4635
Relay_Log_Space: 120
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 1045
Last_IO_Error: error connecting to master 'robert@154.17.0.136:3306' - retry-time: 30 retries: 5
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 0
Master_UUID:
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp: 200704 03:52:46
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
1 row in set (0.01 sec)

ERROR:
No query specified

出现上面Slave_IO_State: Connecting表示没链接上然后排查一下问题什么情况,建议检查3个点,可以用可以尝试使用navicat链接一下,看看能不能连接上,如果能连接应该就是账号密码没填对检查一下

1。主服务器防火墙问题
2,端口问题
3,账号密码地址问题

最后我发现是我的账号密码不正确导致没链接上

停止slave然后重新修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
mysql> stop slave;

mysql> change master to master_host='主服务器ip地址', master_user='root', master_password='root', master_port=3306, master_log_file='master-a-bin.000001', master_log_pos= 4635, master_connect_retry=30;
Query OK, 0 rows affected, 2 warnings (0.03 sec)

mysql> start slave;

mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 154.11.0.116
Master_User: root
Master_Port: 3306
Connect_Retry: 30
Master_Log_File: master-a-bin.000001
Read_Master_Log_Pos: 34730
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 30384
Relay_Master_Log_File: master-a-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 34730
Relay_Log_Space: 30558
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 3becbc01-aaf9-11ea-8f6d-52e142c79032
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
1 row in set (0.00 sec)

然后再次查看链接上了,这样就配置完成了!

docker的流程 用mysql为例

先是dockerfile(或者docker pull)生成镜像->然后run生成容器下面介绍步骤

  • 使用dockerfie生成镜像
1
2
3
4
5
6
7
FROM php:7.1
#b把当前目录下的swoft文件拷贝到到容器的html目录里面
ADD ./cdhihi /var/www/html
#设置工作目录当进入容器的目录
WORKDIR /var/www/html
#映射端口
EXPOSE 9000
  • 打包build命令
1
docker build . -t php:7.1
  • 这里的t是给镜像分配一个名字
  • 镜像生成容器
1
docker run -it -p 9000:9000 -v /var/www:/var/www/html php:7.1
  • 解释一下 运行命令

  • -d: 后台运行容器,并返回容器ID;

  • -i: 以交互模式运行容器,通常与 -t 同时使用;

  • -P: 随机端口映射,容器内部端口随机映射到主机的端口

  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

  • -v: 绑定一个卷,这个卷的意思就是硬盘映射把宿主机的文件映射到docker文件中

基础的操作命令就这些

docker-conposer的简介

  • Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。

  • 当对这个不了解一直以为跟dockerfile是一个东西,然后了解过之后跟他完全没关系,他就是一个快速排版的一个工具,然后就是有点像sehll,写的都是docker run里面的命令,下面就简单的用一下mysql为例

1
2
3
4
5
6
7
8
9
10
11
12
version : '3.4'
service :
mysql :
image : mysql
container_name: mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
ports:
- "13007:3306"
volumes:
- ./runtime/data/mysql:/var/lib/mysql
restart: always
  • version 这个是固定的版本号写死
  • mysql 这个就是容器名称,
  • image 镜像名称(首先是先查看你本地有么有镜像,如果本地没有镜像就会去docker 上面去拉取镜像)
  • container_name 自己定义的
  • environment 环境变量,这里设置的是mysql默认的root密码
  • ports 端口映射
  • volumes 硬盘映射,把本地的文件映射到容器中
  • restart always是指当docker重启的时候启动这个实例

这些就简单的使用案例

实现php的冒泡算法,就是把第一个跟第二个做比较,如果第一个大于第二个然后就换位置,如果不大于就轮询下一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$a = [4,5,3,6,8,1,9];
$ca = count($a);

for ($i=0;$i < $ca;$i++){
//这个是第二个值
for($ia=$i+1;$ia<$ca;$ia++){
//比较第一个值是否大于第二个值
if($a[$i] >$a[$ia]){
list($a[$i],$a[$ia]) = array($a[$ia],$a[$i]);
}
}
}

print_r($a);

//输出结果
//Array ( [0] => 1 [1] => 3 [2] => 4 [3] => 5 [4] => 6 [5] => 8 [6] => 9 )

所有的文档标记都是在每一行的 * 后面以@开头。如果在一段话的中间出来@的标记,这个标记将会被当做普通内容而被忽略掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@access        该标记用于指明关键字的存取权限:private、public或proteced 使用范围:class,function,var,define,module
@author 指明作者
@copyright 指明版权信息
@const 使用范围:define 用来指明PHP中define的常量
@final 使用范围:class,function,var 指明关键字是一个最终的类、方法、属性,禁止派生、修改。
@global 指明在此函数中引用的全局变量
@name 为关键字指定一个别名。
@package 用于逻辑上将一个或几个关键字分到一组。
@abstrcut 说明当前类是一个抽象类
@param 指明一个函数的参数
@return 指明一个方法或函数的返回值
@static 指明关建字是静态的。
@var 指明变量类型
@version 指明版本信息
@todo 指明应该改进或没有实现的地方
@link 可以通过link指到文档中的任何一个关键字
@ingore 用于在文档中忽略指定的关键字

规范注释的php代码 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?php  
/**
* 文件名(sample2.php)
*
* 功能描述(略)
*
* @author steve <liuzhiqun@facedoing.com>
* @version 1.0
* @package sample2
*/

/**
* 包含文件
*/
include_once 'sample3.php';

/**
* 声明全局变量
* @global integer $GLOBALS['_myvar']
* @name $_myvar
*/
$GLOBALS['_myvar'] = 6;

/**
* 声明全局常量
*/
define('NUM', 6);

/**
* 类名
*
* 类功能描述
*
* @package sample2
* @subpackage classes(如果是父类 就添加)
*/
class myclass {

/**
* 声明普通变量
*
* @accessprivate
* @var integer|string
*/
var $firstvar = 6;

/**
* 创建构造函数 {@link $firstvar}
*/
function myclass() {
$this->firstvar = 7;
}

/**
* 定义函数
*
* 函数功能描述
*
* @global string $_myvar
* @staticvar integer $staticvar
* @param string $param1
* @param string $param2
* @return integer|string
*/
function firstFunc($param1, $param2 = 'optional') {
static $staticvar = 7;
global $_myvar;
return $staticvar;
}
}
?>