前言 Why

macOS在某个版本改版之后,对于文件的权限系统做了升级,同时开启了一个SIP保护功能,导致了基于之前一直的习惯(macos自带的Apache,php)在使用的时候会有诸多阻碍。譬如说,安装一个php扩展的时候,就会遇到各种各样的问题,安装过程不能顺利进行。 类似于: PHP 安装扩展报错 grep: /usr/include/php/main/php.h: No such file or directory 包括我们要在www目录下做修改,也不是那么方便。

基于brew,可以傻瓜式的安装和配置好nginx+php开发环境,之所以选择nginx环境,因为生产环境中也是使用的nginx,保持统一比较方便。


安装酒桶 install homebrew

https://brew.sh https://github.com/homebrew/install#uninstall-homebrew

install

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

uninstall

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)"

不建议换镜像/源,换了之后可能会出现无法正常使用的问题,我自己就遇到了,重新安装折腾了我一夜。

最好是使用高速稳定的VPN下载官方源。

下载时总是出现 fetch failed , early EOF 这样的错误。

安装core的时候比较容易出现这个问题,因为仓库整体很大,所以经常会因为网络波动而中断,我参考了网上很多尝试解决的方式都无效,比如说设置postBUFFER, packalimit之类的。

我的解决办法是,使用git clone命令,先将仓库克隆到用户文件夹下,之后删除(替换)brew目录下面的 homebrew-core目录。

git proxy

对git使用代理

vi ~/.gitconfig

添加代理配置 一般代理配置的地址和端口号在代理的说明中会有。

[http "https://github.com"]
    proxy = 127.0.0.1:19180

安装NGINX install nginx

brew install nginx

Docroot is: /usr/local/var/www

The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo.

nginx will load all files in /usr/local/etc/nginx/servers/.

To have launchd start nginx now and restart at login:

brew services start nginx

Or, if you don't want/need a background service you can just run: nginx

补充

#测试配置是否有语法错误
nginx -t

#打开 nginx
brew services start nginx

#重新加载配置|重启|停止|退出 nginx
nginx -s reload|reopen|stop|quit

多个网站的配置

/usr/local/etc/nginx/servers/ 在这个目录下,新建多个需要的 xxx.conf nginx会加载所有的配置文件。


安装PHP install php

通过brew安装php,如7.4

brew install php@74

安装完成后会提示:

To enable PHP in Apache add the following to httpd.conf and restart Apache: LoadModule php7_module /usr/local/opt/php@7.4/lib/httpd/modules/libphp7.so

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

Finally, check DirectoryIndex includes index.php DirectoryIndex index.php index.html

The php.ini and php-fpm.ini file can be found in: /usr/local/etc/php/7.4/

php@7.4 is keg-only, which means it was not symlinked into /usr/local, because this is an alternate version of another formula.

复制提示的代码,将新安装的php设为环境变量:

If you need to have php@7.4 first in your PATH, run:

echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc

补充 (source才能生效)

source ~/.zshrc
php -v

For compilers to find php@7.4 you may need to set: export LDFLAGS="-L/usr/local/opt/php@7.4/lib" export CPPFLAGS="-I/usr/local/opt/php@7.4/include"

To have launchd start php@7.4 now and restart at login: brew services start php@7.4 Or, if you don't want/need a background service you can just run: php-fpm

nginx - php

安装完php后,需要修改nginx的配置来启用php

如果不需要单独配置多个服务器,直接修改nginx.conf即可,如果需要多个,则在servers文件夹下,新建单独的xx.conf文件。

conf文件模板为

server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
        root /Users/mac/dev/web_server/qiyouyun;
        location / {
            index  index.html index.htm index.php;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
}

如果打开测试的php时看到,file not found。很大可能是root目录配置错误。 特别是nginx.conf中,分别需要对 .php和默认的 root设置。

忽略其中一个可能就造成找不到文件。 权限问题可能性不大,不过如果确认目录没问题,可以考虑检查一下权限。

配置完成后,重新加载nginx的配置

nginx -s reload

安装php库管理工具 composer

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer -v
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 2.0.11 2021-02-24 14:57:23

安装扩展 extensions for php

php-zip

下载,或使用wget

wget http://pecl.php.net/get/zip
cd zip-1.19.2
ls

查看一下包是否已经解压,能否ls的时候看到里面的文件结构,如果还是一个目录文件,则再进入,知道可以看到含有install.sh这样的文件。

phpize

Configuring for:
PHP Api Version:         20190902
Zend Module Api No:      20190902
Zend Extension Api No:   320190902

查看一下本地php-config的所在目录

which php-config

/usr/local/opt/php@7.4/bin/php-config

对于当前正在使用的版本进行配置

./configure --with-php-config=/usr/local/opt/php@7.4/bin/php-config
make
............
make install
............


cp ./.libs/zip.so /Users/mac/env/zip-1.19.2/zip-1.19.2/modules/zip.so
cp ./.libs/zip.lai /Users/mac/env/zip-1.19.2/zip-1.19.2/modules/zip.la
----------------------------------------------------------------------
Libraries have been installed in:
   /Users/mac/env/zip-1.19.2/zip-1.19.2/modules

这里的 zip.so是很重要的,开启扩展的时候需要用到。

编辑php.ini

在php.ini中,添加一行扩展信息。(建议添加在 extensions部分)

;extension=pdo_odbc
;extension=pdo_pgsql
;extension=pdo_sqlite
;extension=pgsql
;extension=shmop
extension=/Users/mac/env/zip-1.19.2/zip-1.19.2/modules/zip.so

php-redis

不需要机械的记忆冯诺依曼体系结构的各个组成部分,可以结合他所提出的改良建议来总结。

基础逻辑其实通篇看完后最大的感觉就是如果按照自己用编程逻辑来模拟一个计算机的基本工作逻辑,就发现很多细节是很容易理解的。

  1. 首先计算机体系结构离不开核心的计算结构,而在初期的电子计算机上,编程还需要靠手动改变线路来改变计算逻辑,冯诺依曼提出可以简化这个部分将“程序”直接以数据的形式存储在存储器中。《EDVAC的报告草案》

  2. 计算的进制应该是二进制 而并不是十进制 (这个点就要佩服数学家冯诺依曼了,毕竟一个一直都在跟十进制打交道的人,提出来使用二进制,真的是对数的理解和我们不是一个层次)

  3. 计算机应该还具有5个组成部分, 分别是 运算器,控制器,存储器,输入设备,输出设备

这里将 运算器+控制器 合二为一就是我们现在现行的CPU了 现代CPU中通常就有 计算单元、控制单元、 高速缓存等几个重要组成部分。

CPU内部的结构通过内部总线相连,

CPU与存储器之间通过系统总线相连,系统总线包括了 逻辑总线,地址总线,数据总线。 地址总线的宽度决定了CPU能够管理使用的存储器地址数量,即可用内存大小。 如32位宽,可管理 2的32次方个地址。

存储器主要指的是内存,硬盘其实应该算是外设 存储器的存储单元位宽是一个存储单元能够存储的字节数

存储器中也划分了几个不同的模块,控制逻辑,译码器,地址存储器、数据存储器

因为一些学习和研究目的,最近在写一些数据抓取的组件,在网页上很常见的是相对链接,有时候因为所在网页和相对链接的关系不太确定,所以就需要转换一下,本来这个功能实在太简单,直接在网上搜索了一下,但是发现绝大部分代码都是错的,或者说不严谨,随便改一个目录深度就会发生错误。 这里贴一下我的解决方案:

<?php


class spider{

/*
$rel            string      相对链接
$baseURL    string      当前所在页面完整地址
*/
    public function absoluteURL( $rel, $baseURL ): string
    {
        // 忽略绝对地址
        if ( strstr( $rel, 'https:/') || strstr($rel,'http:/') || strstr($rel,':/') ){
            return $rel;
        }

        // 结构化当前URL
        $url = parse_url($baseURL);

        $rel = trim($rel);

        $depthPath = [];
        foreach ( explode('/',$url['path']) as $i => $p ){
            if( $p != '' ){
                $depthPath[] = $p;
            }
        }
        $pathDeep = count($depthPath);

        $relDepth = [];
        $rootPath = false;
        $backPathDepth = 0;

        if( strstr($rel,'/') ){

            foreach ( explode("/",$rel) as $i => $r){
                if( $i==0 && $r == '' ){ // 直接根目录
                    $rootPath = true;
                }
                if( $r != '' ){
                    $relDepth[] = $r;
                }
                if( $r === '..' ){
                    $backPathDepth++;
                }
            }
        }else{
            $relDepth = [$rel];
        }

        $new_url = $url['scheme'] . '://' . $url['host'];

        if( !$rootPath ){
            for( $i = 0; $i < $pathDeep - $backPathDepth; $i++ ){

                $new_url .= ('/' . $depthPath[$i]);
            }
        }

        for ( $i = 0; $i < count($relDepth); $i ++ ){

            if( $relDepth[$i] !== '..' && $relDepth[$i] !== '.' ){
                $new_url .= ('/' . $relDepth[$i]);
            }
        }

        return $new_url;
}

版本管理在编程中的重要程度不言而喻,其中git工作流也是最主流的方式,接下来总结一下git工作流中的一些比较实用的概念和具体方法。

在实际使用中,我还是用图形软件 sourcetree为主,不过图形软件只是为了方便,并且有很多用法还是要实用命令行来解决,所以要先理解概念,再熟悉命令,最后使用工具。

最常规的几个命令 init, add, rm, status, diff, commit 分别用来 新建仓库、添加、删除、查看概览、比较更改,提交更改。 基本上有这几个命令就可以顺利进行本地仓库的“备份”了。 clone, pull, push 是基于网络管理仓库比较常用的命令,用于 复制仓库,拉取更新,推送更新到服务器。

在git工作流中,协作的重要性是很高的,随着项目规模的升级,以及更多的人使用项目(fork),基于协作的共同维护就很有意义了。

这里主要有两个协作方式 1. 成为维护开发者 2. 创建分支、提交推送

第二种方式,不仅可以用于为源仓库贡献代码,也可以作为“定制化”开发的一种可行途径。这时候如果觉得自己开发的某些代码对于源仓库也有价值,可以再考虑贡献回去。

在github中,成为协作者主要是使用invitation功能,成为维护开发者之后,就可以和创建人一起管理仓库了。

当没有足够认可成为维护开发者,或者只是希望做一些定制化开发留为己用的时候呢,可以使用GitHub的fork功能。

这里我设计了一张图来诠释fork时,repo之间的关系。

在fork之后,实际上我们不必把自己的仓库当成是树枝,当我们创建完分支后,两个仓库已经是对等的了。我们可以向源仓库推送更新,也可以把源仓库的更新当做推送方,合并到自己的仓库中。

在github中,两个仓库之间的拉取是很简单的,无论是希望推送,还是希望从源仓库更新都适用这个拉取。 如果是希望更新就将两个仓库的顺序对转然后进行对比。

之后就根据需要进行合并操作就可以了。

如果是贡献代码,那么需要源仓库开发者通过并且选择再合并。我们更新则是自己来通过。


移除所有记录中的文件

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch THE_FILE_PATH' --prune-empty --tag-name-filter cat -- --all
git push --force

在2019年末的时候,苹果总算是姗姗来迟推出了服务端通知功能,在2020年中下旬推出了退款通知,做过微信、支付宝支付的同学应该很了解这个模式了。 这个模式在微信、支付宝支付中通常的流程都是前端发起了支付行为,前台会即时的返回一个收款确认,而在很短的一段时间后,支付平台会向我们的服务器端发送 一条(得不到正确响应的时候会多次间隔发送)通知请求,一般称之为Notify。

Notify一般会加密携带订单的支付数据,成功与否等,相当于给后端一个比较安全的确认,因为前端即时的反馈数据并不能保证绝对的可靠。 早前在做苹果的应用内支付的时候就对苹果没有回调通知感到很苦恼,因为确认只能自己从服务端向苹果发送验证请求,而且通常是要二次确认才能判断充值是否有效。

这次苹果更新了服务端通知功能,当然是用起来了。

- 阅读剩余部分 -

There are three fundamental Kits in iOS development framework named "OpenGL ES", "Metal", "SceneKit" and an extended kit named "RealityKit" for 3d development. The "ARkit" is functional for both 3d and camera display that render a 3d scene in the camera environment.

So how to add a 3d scene to an iOS project by a .scn file? Actualy we can add the 3d scene by other format like "usdz", ".dae", ".abc". see at AppleDeveloper

1. Create a scene assets folder

If we build a mixed app with UIKit and SceneKit, the prefered way is to create a specific assets folder to manage our 3d resources. Then put the meterial files, or we can create a new scene (.scn file) in it.

It is easy to create a simple scene in Xcode using File > New File, and it will automatically create an scn file.

- 阅读剩余部分 -

Swift泛型

swift 泛型使用 <Type> 来声明

func plus<Number>( _ a:Number, _ b:Number ) -> Number{
    return a+b
}

可以同时声明多个无关的泛型,使用,分割 <TypeA, TypeB>

Swift 函数定义

(Int,Int) -> Bool
(Double) -> Void // (Double)
() -> Array<String>
() -> Void

var foo: (Double) -> Void

func doSometing( what: () -> Bool )

Swift 中 struct 与 class的区别

struct class
Value Type 值类型 Reference Type 引用类型
在swift中是 copy on write 任何时候都是传递指针
Funcional-programing 函数式编程 Object-programing 面向对象编程
不能继承 可以继承
可变性需要被精确描述 默认可变

private(set)

private(set) 表达只在set时处于private 而可以正常读取 这样就避免了大量写 set,get

Identifiable

在swift 使用 ForEach 迭代的时候,需要迭代体内的元素是可以迭代的(每个元素要有可唯一区别性)这时候,可以让元素继承(接受) Identifiable接口

struct student: Identifiable{
    id:Int,
    name:String
}

ForEach( students ){ index in
    // ...
}

Php8在性能上有了一定的提升,接下来看一下对于7.x的版本迁移有那些需要注意的,新版本带来的新特性有哪些适用性。

新特性的介绍源于 php官方文档: Php8

named arguments

命名属性

推荐 好处不用多说了,语法能力提升,自然编程的自由度,便捷度也更好

这一项在面向对象语言中比较常见,类似于C++中的重载就允许实现类似的作用,但是C++的重载实现的能力更强一些,在swift中也是有类似的语法实现。 这个更新总体来说是预言特性上的补足,在7X版本中虽然IDE可以补充参数名显示,但是参数本身是有强制顺序的(如果写了最后一个参数,那么中间所有参数都必须补全),对于有写面向对象语言习惯的人来说这一点应该是比较实用,方便的。


function testArguments( $name, $age = 18, $gender = 1, $isStudent = false ){
}

// php7
// 如果中间两项都是默认,也必须提供参数(NULL)
testArguments( "jack", null, null, true );

// php8
// 可以直接跳过使用默认值的参数
testArguments( "jack", isStudent: true );

Attributes

属性?

也就是说以php官方提供的形式来进行文档注释

不推荐 phpDoc注释显然比官方提供的注释要臃肿,但可读性也更好,一味的简洁不太明智

Constructor property promotion

构造函数中定义属性?

从描述来看,其实是给了一个默认属性和构造函数简便的写法。

对比C++和swift来说,这个增强只能说聊胜于无,因为他并没有直接解决类属性的默认值问题。 而是把默认值的定义放在构造函数中,也就真的和官方说明一样,少写几个字而已。

- 阅读剩余部分 -

我在学不定积分的时候遇到了很多习题都没有找到求解的方式,在看课程(高等数学-宋浩)的时候也经常对

“ 把XX提出来到dx里面,………… ” 这样的一句话十分困惑,特别是对这句话一知半解的时候,再遇到 ∫arctan(√x) d(√x) 这样的式子出现一脸懵的情况。

于是我重新分析了换元公式,总算找到了一个更容易理解的方式来掌握这个知识点。

首先看课本上定义的换元公式(同济7版 p194):

$$ \displaystyle \int f[\phi(x)]\phi^,(x) dx = [ \int f(u) du ] _{u=\phi(x)} $$

我们对这个公式简单做一点改动:

$$ \displaystyle \int f(x)g(x) dx = \int f(x) d[\int g(x)dx ] $$

什么意思呢,积分式子中的一部分(乘除法 (加减法可以直接拆开两个) ) 可以求积分,直接放到积分变量中去,这样是不是比书上的容易理解多了。

- 阅读剩余部分 -

在做习题的时候出现了一个小纰漏,原因是想当然的把 ƒ²(x) 的导数当成了 x²的导数。 从原理上来说 ƒ²(x) 应该当作 ƒ(x) 的复合函数来求导,也可以当作是 ƒ(x) * ƒ(x) 来计算。

ƒ(x),g(x)可导,ƒ²(x)+g²(x) ≠ 0,求

$$ y= \sqrt {f^2(x)+ g^2(x)} $$

的导数。

另外就是 e2t 的导数求法了,这也是很容易就疏忽写错的。 每次求导一定要注意,前一层复合函数中作为主变量在后一层中,是否是一层函数。

(e2t)' = e2t * (2t)' = 2e2t