主要记录学习过程中一些容易遗忘的点
基础操作
- mb_strlen($str, ‘utf8’):在utf8下,显示中文的字符数,否则在utf-8中文字符是长度为3,gbk或gb2312中文字符长度为2,拓展阅读;
- explode(demitter, $string)和implode(demitter, $array):前者是把字符串根据demitter拆开变成数组,后者是把数组根据demitter组合成新的字符串;
- 定义常量有两种方式:define(‘CONSTANT’, ‘helloworld’, true); 或者 const CONSTANT = ‘helloworld’; 后者常用在类中定义常量,php5只能接收标量类型,php7还能接收array类型;常量可以直接echo CONSTANT; 也可以constant(CONSTANT);
- get_defined_constants():可以用来检查所有系统常量;
- require()是强加载,报错的话不会继续执行,include()则会继续执行;
- 开启严格模式 ```php <?php declare(strint_types = 1) function show(int $num) { return $num; } var_dump(‘2’); // 此时报错 因为已开启严格模式
function show2(int …$nums): int { return array_sum($nums); } echo show2(1,2,3,4,5,5);
7. 变量的**作用域**:php的变量作用域和JS有很大的不同,函数内部无法访问外部/全局变量
```php
<?php
$name = 'gaohang';
function show() {
global $name; // 1.引入name
echo $name;
echo $GLOBALS['name']; // 2.超全局变量
}
function show(&$name) { echo $name; } // 3.使用传值的方式
show();
- static关键字:使变量在函数内持久保留;
变量函数,由此可见函数名实际上是string,此外function_exists()可以检查某个函数是否存在
<?php
function sum() {
echo 'sum function';
}
$name = 'sum';
echo $name();
数组操作
list()方法在遇到关连数组时,要这么使用,下标=>变量名,变量名可以随意,同索引数组一样 ```php <?php $arr = [‘name’=>’gaohang’, “age”=>25, “height”=>178]; list(‘name’=>$name, “age”=>$age, “height”=>$height) = $arr; echo $name, $age, $height;
// php7下正常 $fruit = array(‘a’ => ‘apple’, ‘b’ => ‘banana’, ‘c’ => ‘cranberry’); while (list(‘key’=>$k, ‘value’=>$v) = each($fruit)) { echo “$k => $v\n”; }
10. 数组常用的api:
1. array_key_exists($key, $array); 检查某个key是否存在于某个数组中;
1. in_array("Runoob", $sites); 某个值是否在某个数组中;
1. array_keys(); 返回包含数组所有键名的数组,等于提取了数组所有键名组成新数组,同样array_values()返回各项值组成的数组;
1. array_change_key_case($array, 1); 将数组所有key转换为大写;
1. array_walk($arr, function($value, $key, $type), CASE_UPPER):对数组中的每个元素应用自定义函数;
11. var_export($array); :以**合法的php语法**形式返回一个php变量,第二个参数为true则不执行,反而是赋给一个变量;
11. serialize/unserialize:序列化,把数组变成字符串;
11. foreach操作一定要记住,as后面只有一个参数时,指代的时value,两个参数时时$key=<$value!
<a name="I49W3"></a>
# 日期操作
13. _date_default_timezone_set_('PRC');设置时区;
13. strtotime('2020-04-16'); 字符串时间转timestamp,再用date('Y-m-d H-i-s', 1586988000); 可以再转回字符串时间;echo _date_("Y-m-d", _strtotime_('+1 year')); 可以用灵活的时间关键字,如next friday等等;
13. time(); 返回10位timestamp;Date("Y/m/d"); // 2020/04/16 用来把时间格式化成人看的时间;
13. _print_r_(_date_create_('2020-04-16')); 返回一个DateTime对象
```php
<?php
print_r(date_create('2020-04-16'));
(
[date] => 2020-04-16 00:00:00.000000
[timezone_type] => 3
[timezone] => Europe/Berlin
)
双问好:双问号取后面的值,
echo min($total, max(1, $_GET['page']??1));
若page未定义为null,则直接取1;正则操作
preg_match(‘/\d/‘, ‘qwdq333’); // 1 代表true
- preg_match(‘/[abc]/‘, ‘a’); // 1 [abc]表示原子表,即字符串只要满足表中任意一个字符即可;
- preg_match(‘/(abc)/‘, ‘abcd’); // 1 (abc)表示原子组,即必须满足完成的括号内的条件才可,也可以和或者搭配:”/.(baidu|sina)/“
- 原子组可以和捕获组的概念相结合,注意在PHP中\0指的是整个正则表达式整个
- preg_split(‘/[@#]/‘, $str); // 根据正则来拆分某个字符串成为数组;再用implode把数组变成字符串;
- preg_replace($reg, $replace, $source);
- 选择符:|
- 重复匹配:对应的符号跟在每个原子的后面:* - 任意个字符 + - 至少有一个 ? - 0个或者一个
- 指定具体数量:通过花括号:/^\d{3}$/ - 只能有两个数字 /^\d{2,6}$/ - 限定2~6个
- 注意 php中单引号不做转义或解析,双引号必须给特殊字符做转义才能被正确解析;
- 贪婪匹配,可以通过加?来取消贪婪匹配,还可以通过修饰符来取消贪婪模式,”#
.<\/h1>#U”,更为方便 ```php <?php $str = “
厦门
天气晴热
“; $reg = “#.<\/h1>#”; preg_match_all($reg, $str, $subject); print_r($subject); Array ( [0] => Array
(
[0] => <h1>厦门</h1><h1>天气晴热</h1>
)
) // 取消贪婪匹配 $str = “
厦门
天气晴热
“; $reg = “#.*?<\/h1>#”; preg_match_all($reg, $str, $subject); print_r($subject); Array ( [0] => Array ( [0] =>
厦门
[1] =>天气晴热
))
<a name="3E8Lt"></a>
# 文件操作
1. 磁盘资源
```php
<?php
function space_total(int $total): string
{
$config = array(3=>'GB',2=>'MB',1=>'KB');
foreach ($config as $num=>$unit) {
if ($total > pow(1024, $num)) {
return round($total / pow(1024, $num)) . $unit;
}
}
return $total.'B';
}
echo space_total(disk_total_space('.')) . "<br/>";
echo space_total(disk_free_space('.'));
- 打开文件:fopen($filename, $mode);,打开错误则返回FALSE并附带错误信息(@符可以隐藏),下面主要说说打开的各种模式:
- r:只读模式,指针在文首
- r+:读写模式,指针在文首
- w:写入,完全重写也就是会清除内容
- w+:读写模式,也就是返回文件内容,其余与w没有区别,照样是重写内容
- a:写入方式打开,从文末写入,更加符合直觉的一种操作
- a+:读写方式打开,通过将文件指针指向文件末尾进行写入来保存文件内容
- 读取二进制的时候要用rb
- x:创建一个新的文件并以写入方式打开,如果文件已存在则返回 FALSE 和一个错误,适合于新建文件的操作
- x+
- file_exists($name):是否存在
- 读取文件:fread($resource, length); 全部读取需要借助filesize($filename)来作为length;读取文件一定要记住此时的指针指向哪里,就从哪里开始读!
- 控制文件指针:fseek($resource, int offset); 说白了就是移动光标来获取某个内容;
- 写入文件:fwrite($resource, $string); 要写入内容,所以fopen的模式必须是r+,表示需要写入内容,注意此时默认光标是在第一位,所以会覆盖内容,要在尾部继续写需要用fseek($resource, filesize($filename));
- 关闭文件:fclose(); 关闭文件后指针又会跑到文档第一位;
- feof($handle); 返回当前文件指针是否到达末尾,经常配合while来循环读取所有文本;
- fgets($handle, length); 返回一行文本,前提是没有遇到换行符等等;
- fgetc($handle)l 返回一个字符,只接受一个文件资源参数;
- fgetcsv($handle, $seperator); 更具分割符返回成数组个十年;
- flock($handle, LOCK_SH); 共享锁,大家都可以读,限制写,上锁的代码执行完成后可以自动解锁,或者flock($handle, LOCK_UN); 手动解锁,如果是flock($handle, LOCK_EX); 则是独占锁定,即写入,同时排斥别人访问这个文件;
- $stat = flock($handle, LOCK_NB, $wouldblock); 锁不成功它不会等待也就是不会阻塞,返回false,而是解开继续向下执行。常用这个进行判断条件,为true则执行fwrite,为false则弹出文件被锁提示,第三个参数表示是否被锁定
- 文件权限:写入权限 - is_writable($filename); 读取权限 - is_readable($filename);
- 各种检测:is_dir(‘../79’); is_file($filename); file_exists($filename);
- 快速读取与写入文件:
- file_get_contents(path)
- file_put_contents(file, data, mode[FILE_APPEND | LOCK_EX]);
- filemtime() 函数返回文件内容的上次修改时间; filetime()经常用来判断缓存;
- 文件相关常量:
- FILE:完整路径带文件名
- DIR:只包含完整目录,不包含文件名;
- DIRECTION_SEPERTOR:文件分隔符;define(‘DS’, DIRECTION_SEPERTOR);
- basename(); 路径字符串中取文件名;dirname(); 取路径名;mkdir(‘test’, 0755, true); true表示递归的创建目录,也就是多层的创建目录;rmdir(‘test’); 删除目录; rename(‘hd.txt’, ‘a/hd.txt’); 重命名和移动两个特性;copy(‘a/hd.txt’, ‘./hd.txt’); unlink($file); 删除文件
- scandir(‘.’); 返回一个数组,即当前目录下所有文件; print_r(glob(“.“)); 返回数组
- 目录操作与递归 ```php <?php // 通过递归统计每个目录的文件大小 得出目录占用空间总大小
```
关于文件的访问,创建和最后修改时间的函数
静态属性:static声明一个变量为静态变量,只能被类本身调用,无法被类new出来的实例调用,写在class中经常用来表示公用的变量;此外,php在类中提供了关键字self来指代当前class:self::$static_value;
- 静态方法:同上,只能用类来调用,所以内部不能用$this对象;
- 类常量:他的作用域在类的内部,也是必须使用类来调用类常量,方法内部使用self调用,适用场景在于类的使用过程中不会改变的数据;
- 继承了方法后,就可以直接用$this->调用继承的类方法。
- Final:子类可以重写父类的方法,可以在父类中用final关键字,防止某个方法在子类中被重写。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
- 抽象类:通过abstract把一个类定义为抽象类,然后再定义一个抽象方法:abstract public function content ();注意这个方法不用去实现,这样子类继承的时候必须在子类中实现父类中定义的抽象类,保证程序的健壮性!
- 接口就是规定统一实现的某个动作的方法名,接口只是定义规范但不做任何实现:public function set($name, $vaslue, #expire);规定接口后,我们在写类的时候就要去class Mysql implements Cache { … } 实现某个接口;
- 调用父类的方法:有时候我们想调用父类的方法,但这个方法在子类中被重写了,此时需要用parent::message();来调用;
- 变相实现多重继承,父类用trait取代class进行声明:trait Log { … }; trait Comment { … };,要继承的子类内部use Comment, Log;,我们要把user理解为继承!
- 如果子类调用了继承类和trait类中都有的同名方法,则trait类优先!
- 如何解决trait冲突呢?引用了同时use的两个trait类都有的同名方法,此时会报错,可以用如下的方法来解决,即用Log类的save方法取代comment类,想用comment时再给其内部的save方法取一个别名!
- 访问控制:声明为protected的方法在外部子类是无法调用的,理解为被保护的类,只能在类的内部访问,不需要提供到外部
- private关键字也能达到protected的效果,但区别在于继承,也就是说父类中定义了protected修饰的方法,可以在子类内部中$this->调用(注意哦,不能被new出来的子类实例调用),而private也不允许这样的操作,也就是父类方法不让子类用,就父类自己能用!
- trait类也可以继承trait类;
- 注意!静态方法既可以通过实例化的对象调用(->符号),也可以通过类直接调用(::符号);
- 析构函数:当函数不用的时候需要卸载的时候,统一的执行某个操作,与__construct的执行时机相反;
- 当调用一个不存在方法时,就会自动调用public function __call() { … }; 方法。
- __callStatic(); 魔术方法在你调用一个无权访问或不存在的静态方法时被自动调用;